From 6c29cee70078def58b08724ff43e170c6ce6e9e4 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 27 Nov 2017 01:22:16 +1100 Subject: [PATCH 001/381] 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 b1f3aadb52bb4f6714da011130b5305c474f066a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 27 Nov 2017 08:33:59 +1100 Subject: [PATCH 002/381] 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 59d1f13648227052eedd5aa6fdded9bfd9d32737 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 20 Dec 2017 17:30:25 +1100 Subject: [PATCH 003/381] 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 35d623aa35919abcb40143797f25e12bfb2329ae Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 20 Dec 2017 17:30:34 +1100 Subject: [PATCH 004/381] 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 ce4d4bfb1a75cc0e2dc30d69d81f23dd7811b556 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 21 Dec 2017 09:33:19 +1100 Subject: [PATCH 005/381] 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 2c3dc41eacdf6ed99bb1227e25b29d6bc027b4e8 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 1 Mar 2018 23:44:32 +1100 Subject: [PATCH 006/381] 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 3cd9cff600b12d39af10106be9bf2b15a07b8e40 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 2 Mar 2018 00:39:17 +1100 Subject: [PATCH 007/381] 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 01f24998f274ab81c8d1bbc57b35659450b2d0eb Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 2 Mar 2018 00:46:05 +1100 Subject: [PATCH 008/381] 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 f4c0ffefc1018d857cdf48904ff8206f971cef44 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 2 Mar 2018 14:10:03 +1100 Subject: [PATCH 009/381] 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 be709df199b4f5f21f0b4fabc3c2180ef0357e1d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 3 Mar 2018 22:28:46 +1100 Subject: [PATCH 010/381] 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 f5b8abaf25d62092d074826daf8df20b66a3e51b Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 3 Mar 2018 23:51:48 +1100 Subject: [PATCH 011/381] 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 1223f786240d05cd7c2abd80565389a7b747dd1e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 12 Jul 2018 19:44:18 +1000 Subject: [PATCH 012/381] 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 72b292abc771aa65ada62b040a0ca46bda65ba8a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 14 Jul 2018 22:42:15 +1000 Subject: [PATCH 013/381] 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 1f375b17f6800084c7136f954dff6b630abafd8f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 15 Jul 2018 17:07:30 +1000 Subject: [PATCH 014/381] 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 baa7ebe2c59756066f49aa0b4157a480c24c11bc Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 15 Jul 2018 22:49:50 +1000 Subject: [PATCH 015/381] 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 babe6e49b66d0ed8ae1ed0de2a262d6329ab3018 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 15 Jul 2018 23:15:02 +1000 Subject: [PATCH 016/381] 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 e77ddd215223db93e0b2924602f5b9aeace7dfe6 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 16 Jul 2018 00:14:03 +1000 Subject: [PATCH 017/381] 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 5cc0e8b2358a0111624a90036e6feec0ad65015b Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 23 Jul 2018 08:53:21 +0100 Subject: [PATCH 018/381] 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 71bd4c9887f0f80e361bef75665ee9d66500b61f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 26 Jul 2018 19:17:35 +0100 Subject: [PATCH 019/381] 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 8966e7d274dcbb209e4508eef092d5861c81bfb1 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 27 Jul 2018 15:04:32 +0100 Subject: [PATCH 020/381] 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 f04b1e7b253f730a837d1df7d066240c4390493f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 27 Jul 2018 15:55:09 +0100 Subject: [PATCH 021/381] 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 6bd974f55a384973385f27f07a0877ab64c94504 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 27 Jul 2018 18:59:39 +0100 Subject: [PATCH 022/381] 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 7f3cdc805288cccbe1033117bab6c0875243f494 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 28 Jul 2018 15:53:35 +0100 Subject: [PATCH 023/381] 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 0d2788752c137e9880d697fc3c36736f8ad1d2a0 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 29 Jul 2018 22:58:16 +0100 Subject: [PATCH 024/381] 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 a5ec503a4f39fcbfa09438986003cf462e5f7cfd Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 30 Jul 2018 14:25:39 +0100 Subject: [PATCH 025/381] 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 b3c1ef7ee8c35823ff8ee1ff1877699dd36ab32a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 30 Jul 2018 14:25:48 +0100 Subject: [PATCH 026/381] 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 1bcdb31716ef5d13f7424c962c7c750d9708bad8 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 30 Jul 2018 15:38:46 +0100 Subject: [PATCH 027/381] 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 e516dfe82f073e4f2968db7966d76c641de08da4 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 30 Jul 2018 16:13:44 +0100 Subject: [PATCH 028/381] 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 ba040d78eb525ec4a2053718d514f88ba9e906a6 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 1 Aug 2018 08:36:12 +0100 Subject: [PATCH 029/381] 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 fbb1318c4c6939f4740b749c04b694b3d5727be3 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 5 Aug 2018 17:42:17 +0200 Subject: [PATCH 030/381] 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 c094e12ba7f0e1fed7cd476abd73552eef15f937 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 14 Sep 2018 00:16:10 +0200 Subject: [PATCH 031/381] 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 4bfafc97b59849ba3f4fce47102ac8e4d0d4e9ed Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 15 Sep 2018 18:36:38 +0200 Subject: [PATCH 032/381] 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 feb1a4435653e2a4d355118713357972d64dc053 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 15 Sep 2018 19:43:02 +0200 Subject: [PATCH 033/381] 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 2bc0c17f41f71d46d8a5f7b541d29ce0c5b5bcca Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 18 Sep 2018 21:04:46 +0100 Subject: [PATCH 034/381] 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 | Bin 245033 -> 5081 bytes 27 files changed, 121 insertions(+), 206 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 0964ae9744027325bd6a2a19b2247c39f8349ca1..c30f0a86927b58643661c0bf0cf5815eebd51790 100644 GIT binary patch literal 5081 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

9-wuN@I_bMT-{6~VrL!0uIPW5LfW3ICSi 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 From eefe27409b4c829ed648a5c1041c303f33cb537a Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 00:28:44 +0200 Subject: [PATCH 035/381] 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 3a0ed0b338801a737ce5eb15750b05e280979e16 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 00:39:56 +0200 Subject: [PATCH 036/381] 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 55479b0dee1bcb57bf0d641a0fc23b95d0896ef1 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 00:55:42 +0200 Subject: [PATCH 037/381] 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 55b30e8a28e2a71677f8403094649105f04bf888 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 15:07:01 +0200 Subject: [PATCH 038/381] 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 00992043bbdf11237da3b5530bf886ff95f36e7e Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 17:25:47 +0200 Subject: [PATCH 039/381] 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 553a14952cefafb75bfc1a37ed961b950d1e04b6 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 19:14:52 +0200 Subject: [PATCH 040/381] 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 d70fbc69d01ce15703b48dc7f41883da72d58f5f Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 19:42:45 +0200 Subject: [PATCH 041/381] 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 2bf6278866e70d26f65b703edd50009523e0666c Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 22:14:41 +0200 Subject: [PATCH 042/381] 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 2ee4a88d54b043a29e6aabb0ec2307eb8af38565 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 22:52:30 +0200 Subject: [PATCH 043/381] 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 e11c19c4477809c6cf8698527c1980b939c24c26 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 23:07:24 +0200 Subject: [PATCH 044/381] 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 d0be9fd6b06631c054de638b56e728250931c3bb Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 23:45:46 +0200 Subject: [PATCH 045/381] 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 a4f0475d9d74216356eb79047c5664ede033a418 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 23 Sep 2018 00:45:01 +0200 Subject: [PATCH 046/381] 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 196c8a1a6de9aed62b84130ef8c1bd66e9ecb301 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 23 Sep 2018 01:16:41 +0200 Subject: [PATCH 047/381] 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 f0cda4387bc2a05c15df91e85acfe4417172273e Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 23 Sep 2018 01:30:22 +0200 Subject: [PATCH 048/381] 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 38cb7871a1d4370c00e7c1a1df555aaa761c8950 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 23 Sep 2018 01:35:40 +0200 Subject: [PATCH 049/381] 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 72f0d26d1094ae497f0d5826571dedac254424d6 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 23 Sep 2018 01:43:02 +0200 Subject: [PATCH 050/381] 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 16227a40e8c65849209abeb6f88d7bff43d105b8 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 23 Sep 2018 01:56:05 +0200 Subject: [PATCH 051/381] 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 c7459dd2ff50f59e440037d1241fb93d432f07a5 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 23 Sep 2018 02:01:24 +0200 Subject: [PATCH 052/381] 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 1664670dd8deb634342a332e1e720dda8828a8ae Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 23 Sep 2018 17:41:15 +0200 Subject: [PATCH 053/381] 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 0c42925a05c0d08a9cdebcc46c03004a05cb702d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 23 Sep 2018 20:55:34 +0200 Subject: [PATCH 054/381] 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 be570f70322f8625fe15911f10619917c273e9fc Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 26 Sep 2018 00:38:06 +0100 Subject: [PATCH 055/381] 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 0c267f8d790f0689a4b9c610af715c73fbaf6338 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 26 Sep 2018 12:12:38 +0100 Subject: [PATCH 056/381] 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 7b692fd15af032d91d79848a31e238aff574d623 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 26 Sep 2018 21:17:08 +0100 Subject: [PATCH 057/381] 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 f073fff6a120fcf75471c0891d376761cafa34c3 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 26 Sep 2018 23:22:47 +0100 Subject: [PATCH 058/381] 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 a9e0da2465b824157efae597d5131717da1882a5 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 27 Sep 2018 13:00:42 +0100 Subject: [PATCH 059/381] 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 8540033a6c075d8b68a906c0d9675719fbbc1570 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 27 Sep 2018 15:35:44 +0100 Subject: [PATCH 060/381] 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 6bab44a56a99c0958c416f9f26aec0b3a74c4c8f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 27 Sep 2018 16:03:56 +0100 Subject: [PATCH 061/381] 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 a4e18a9c6d1aa810800b99e35fd2756e751503ef Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 27 Sep 2018 17:39:23 +0100 Subject: [PATCH 062/381] 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 b2dcbb6b4c42fe86ff89641b1434b345c0de3146 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 27 Sep 2018 09:17:22 +0100 Subject: [PATCH 063/381] 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 852bfccc7aca3b12485170944b964f283fd02880 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 27 Sep 2018 09:17:38 +0100 Subject: [PATCH 064/381] 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 389684c4aaa7e129a7ea11ebda3a158a9532b9a5 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Sat, 29 Sep 2018 15:21:45 -0700 Subject: [PATCH 065/381] 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 77b1db8b3b6b36f57570bf70da3d65d545f43c04 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Sat, 29 Sep 2018 15:22:05 -0700 Subject: [PATCH 066/381] 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 3ca91637466e0d4868b69f9c8569ee9b59f58771 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Sat, 29 Sep 2018 15:27:18 -0700 Subject: [PATCH 067/381] 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 07db5ae0b265684de466108d863eb5e532a0a90c Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Sat, 29 Sep 2018 15:33:56 -0700 Subject: [PATCH 068/381] 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 f6874ba1ff28514372c1bab986ce41ce8ee6123f Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Sat, 29 Sep 2018 15:40:25 -0700 Subject: [PATCH 069/381] 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 3e6d3d35b7e86e5bd6f07525b3f5c067a2b26fbb Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Sat, 29 Sep 2018 15:51:40 -0700 Subject: [PATCH 070/381] 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 2e10c1128632eb92ff9ee2797bcd5537ec62e0a8 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Sat, 29 Sep 2018 15:56:00 -0700 Subject: [PATCH 071/381] 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 eec6fc71bc1fb5af9f7229c7a0293afcf720a86f Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Sat, 29 Sep 2018 16:03:50 -0700 Subject: [PATCH 072/381] 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 f5464b589fddd9852b41ad3a2f6293ff96980815 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 073/381] 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 89d867e54dd75ec7183f9337b69c0680b7528c08 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 1 Oct 2018 15:55:35 -0700 Subject: [PATCH 074/381] 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 260994fab36b6f686535b640bec9d6de840a48e1 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 1 Oct 2018 15:57:26 -0700 Subject: [PATCH 075/381] 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 583af0e934d487ba10ff0396688d02b9e1f6b924 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 1 Oct 2018 16:19:24 -0700 Subject: [PATCH 076/381] 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 745a05774a4422308e971ff5f8da68d5803b3664 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 1 Oct 2018 16:23:38 -0700 Subject: [PATCH 077/381] 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 4cf88663bfdf3d0583145af7396d53a091a92303 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 1 Oct 2018 16:48:44 -0700 Subject: [PATCH 078/381] 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 ad2cd609942b7db5c88d0b4daaa4bb14f708e3ef Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 1 Oct 2018 16:51:46 -0700 Subject: [PATCH 079/381] 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 bb37823dc2beb3ab6d7947b6db3bea0074ce34f8 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 1 Oct 2018 16:56:39 -0700 Subject: [PATCH 080/381] 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 759646f6062033c3cb61677173ba96466e40ccc0 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 1 Oct 2018 17:13:22 -0700 Subject: [PATCH 081/381] 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 d5df1dde58b2721edf32ba09063db500abc6957c Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 1 Oct 2018 17:53:07 -0700 Subject: [PATCH 082/381] 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 b284c3da470ebe886473aed19dc38ec8fc95d819 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 1 Oct 2018 18:00:33 -0700 Subject: [PATCH 083/381] 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 d8d2e42a2dc84cc43193d566513292479de68759 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 1 Oct 2018 18:04:32 -0700 Subject: [PATCH 084/381] 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 e609a3a5d8664083ab041977d2537f4ff5e20de7 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 2 Oct 2018 16:12:46 +0100 Subject: [PATCH 085/381] 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 346147a187777384107ef011de25f83fe610f85f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 2 Oct 2018 17:20:08 +0100 Subject: [PATCH 086/381] 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 7845e8660e0d00dd1ccfd6d174da7e5368edeb4b Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 2 Oct 2018 20:16:44 +0100 Subject: [PATCH 087/381] 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 fd0ac3e1e2f906409eac462f66c395dd92a80b86 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 2 Oct 2018 20:17:06 +0100 Subject: [PATCH 088/381] 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 321e439343541bbdbb352b60f9be1962cb5bd548 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 2 Oct 2018 20:24:19 +0100 Subject: [PATCH 089/381] Fix accidentally replaced test image --- tests/Images/Input/Png/splash.png | Bin 5081 -> 245033 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/Images/Input/Png/splash.png b/tests/Images/Input/Png/splash.png index c30f0a86927b58643661c0bf0cf5815eebd51790..0964ae9744027325bd6a2a19b2247c39f8349ca1 100644 GIT binary patch literal 245033 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

9-wuN@I_bMT-{6~VrL!0uIPW5LfW3ICSi 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 literal 5081 zcmeAS@N?(olHy`uVBq!ia0y~yVA;UHz!bs31{5iJCNBk~SkfJR9T^xl_H+M9WCijS zl0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV+ueoXKL{?^ zyL>WGguTSm*OmPtvz)L2_lCGrD;XFBgFIavLn>~)y?rt3c7TZMLFLK+|EJvFb3}pV zx?29}BsQ*G84iwBhu&EopA}hr=1g*0-{tkkpMEd?b!+$ezSG~|+TH#;$GYZOn7YMj6bR65~VivW zIRF~U%#cv_;{b({2Q&nr-a=CfjSx0S+|3aHh0+APN=Ku4G@3_qGo*|_%S^P%ceF7T zwIm)bwDA?%bctrtBV@GDrf%IlNTZqb#?okR9)h`<^k_zHk`mJ<9!V|jVUwFlk7m@K z2QghAViFJOrlR&dM!P;ku!l=b;u%8G4C Date: Wed, 3 Oct 2018 00:26:14 +0100 Subject: [PATCH 090/381] 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 5a75939dff0310a389a77a890bc6f419cfdcffee Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 3 Oct 2018 02:12:09 +0200 Subject: [PATCH 091/381] 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 762c743d20142c2a499df8edcac922398f64b938 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 3 Oct 2018 09:34:26 +0100 Subject: [PATCH 092/381] 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 3af4fb190e5305f8c318c8c88a73ad2b59cac2de Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 3 Oct 2018 17:37:50 +0100 Subject: [PATCH 093/381] 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 54d45d507139ec742e280422c0c4448ba05c5e1a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 3 Oct 2018 19:59:17 +0100 Subject: [PATCH 094/381] 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 eb04ca66b9f911e91563e2d158ab24188c2673f1 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 3 Oct 2018 22:36:57 +0100 Subject: [PATCH 095/381] 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 f62f6e82e13310e0e625d40d9eb9653f874895d8 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 4 Oct 2018 08:27:00 +0100 Subject: [PATCH 096/381] Fix #721 --- .../Formats/Jpeg/JpegDecoderCore.cs | 3 ++- .../Formats/Jpg/JpegDecoderTests.Images.cs | 5 +++-- tests/ImageSharp.Tests/TestImages.cs | 1 + tests/Images/External | 2 +- .../Input/Jpg/issues/Issue721-InvalidAPP0.jpg | Bin 0 -> 1225163 bytes 5 files changed, 7 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 0000000000000000000000000000000000000000..6fa3bf660e9c68969479316ad5f53190893a8544 GIT binary patch literal 1225163 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∓+7Y&F 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 z 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

    9r#1{QX3 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ɜLU73hw+So`Ew4@u)6z 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

    HhSFnhe%kkqIUcQoOgGU8B(FhnO9!H9@u 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

    I+dZS?r2D@h-9Css#qc4@80-U$hI;f zJCmCa1AP8xBmBH7ar9ySU(Qg-*j!bmY*RIp_O(gV`%^MQN?0D1+~f=rLR2T?z*sne z4UW4(T@RWr5Sa`+$E=%Muq_x1XM_p1#*;Bp_WI4E1lyyxU-|Qzq`gXG4d3LPyJ)Ou zlVefr*P>j1ZXXk(IfwS?0VpiJLLUhYo2)~13x(z{=3`cqE#j^4m|hB2%H_y48x=b7 z@<|ec*Wt_2#?5gJ}i=tSiRoZ=@3QWD8*EMBq)5e!|ou=gkLY$8Vr>`C7I&M=D%>u`8Z@kHb&_^kCl zZWo)nyFRgir{xZfmj-t*w)Vn(&IH9~bMg&Sb+FC8dpy){q8AL=(i>@3eee2?Qn`>l zG3s8Q4d$*pdI5P&VAV;zRe8t4mhybyyRyF%-0+txNqUVkNkM&W3~ek#iR_z;B%_$~ z$(7djhYG>=Pt0wRjiwzwr!qsyb#mNaxm8FmR|emx5Anb{7IhdEK1PC2%XmXu7lYiG zzz$*6{hba7`A0LKC>xJoao~N#CboIOYo+Cy(4-MtK_`t)$`#DWlGA!MI(+W1OSkmF zcf77`ybSfdCL+~b3H<9e=9b*8va#Qm6SQ6GK8w`CI^r-d%2Sg_OJhCcv&RZ4L9*q+3|(=(yhI$4)9cv86!(P!>?*jO zTlp7u7wF0ueiuuCce?YE)olICVe7ezv&p)V1pObL3ci~)T1_=t;>62|sg?$KsgTv_ zcBedbkP1|&vML2IslDVnqaE;y5X-Dz$xV}lOWKcq3Mn0AlaMZ0KZ*bo5M)x|MAzFG zQS-Iu?DPAs?^35=rmq>u^;xxa)~kCY>S6FqFQvfd&?R;Z7gLEpl!da+b zmpx($#e_=^$|T9y{2cfu(!$--LDSGg>QME3b{*U(x-NnhtKsxn@a=bym5ZcTeZqAZ zf}ZWVS52fC_-?&RcQ?^pUe6|XMdAph1+$1goca=c1fZ(W! z_G^&j=ODr$4f5GkzWrI;SH<&fz0#*tJGxUcUmBNu-th&f>OGSETv~}M(0=rHRo?kg zRn^0OB$RkuEKf66JWX2!T@08b3a@N@`gzN<>kG>WerxT}%O|zIUH%Q`#wvv7MFHm_OdJ_0DGVFO=gcuFjQv zCc#pKG@3LGJ!V>|$OiSo7kg#FY2?IwN-E0wn<9c)7>d6Cf~+$$p!>Ih5A!Us?+3-w z=3eT=(`rP$sDG?A7uu+a>}%HD7o`C2;^X53%iClY^~iXorT7a}AEILDx{U72A9*a_ z5AoX}0+>2nNVTkNircZ44c$qwjwHrNg4SHAjr#s&-&LA&__p$a8Fs)b3yfDIzAbt) z`JiVX7N1*2suwXHy-IY86RZThS&jtlxMftPDG|XI(+(KPf=CRq>Ib6Blpc?E-S85y zsM)j9IdFHRiQKFh#jxekwav+BNule{F6F9h`$LlWxq%TTG6vI`SJDs8rkx#goo(^z zBUUc{x4BGa`!h1y)Qt=dgSFF_>x3>g2qPh)o!PlB03Vlk<;hAaJ3)Ld#Yf9ChhahS z<-}iKXif*!%g3=z4yMXk%;O~cWaiqx10knkbJDl8_)$v&DT!cC(s&*6qh08AIFF-W zhU#z;@EI=SfOvTh4h_AkziDe%t^PtE=fXzT|FTlFKs>loQ2nc^YbRs=C@NnZww__X zyQ_;4jP{sc+h$BR{ebnQ!#iHLWHJ3Fq4di?ro#@*gINTVT58RK7G~I{$c)O~Ji|DU z(LCs0U%|WFc&3}af3S56Zgls!WR@>}Da$&uWtyWfxv6%4v!$;wXX10941PxkE<#SN zX6jd*$iChFg%5|D$F=wDOa|^p&?d5smn!X?wQ{}+V?(JprpP`4Hw6;=&xyXwuF zNBJ`S2k7g?DO<+8{)3nA)1)i$k7H00AN_?pMl4bPb;1{|JZV&?;_m`E&-1~td`NuC z`vGPZ+6Z5X#aw`MeRhB$%9lcQC>fcQ{H!>T%WSF?^%Z$Z&Q+fll_APxx;U5Mup;n4 zwx80Bb~e+rvStd2CahBjSv=6fRvpdRLWcpNVo>v<&M~qwsMd z&d_ZZ>Wz&(AIVox9)6+fko>)bTYPzl@v+7qahSc0i`d!W4C8b7V1!d<*4MEhi?Km; zSoJXOTm%lPA~tGeb6*>4ozWC0dJ%_S#!!J)nJk~fOTP|eccW%}I{qehKg2}cL|-;Z ztEi|Cl*Z+BXQ=w3sW^O^j}0GcZ9}jbd~Q^4DC)CV7&qH9pTSRkuTrI zj$@trR(>fz9a7k5f5P`2x>Xr`p~IWWTD*ElrRIu1&cLG(1+?A9%w?FvZ*9+)edAS; zp|mk~3GhJrjb*5r0r^f}erG$`(#7YkkH-VhOmCzEk|oN@J+zs_yX4r0Pw%Ib>!pl* z7G`?qL`5O&Y;4?^DRUFZ%qbmnL-jeO)^cwAG^O<3nAPpkXg^P>6S`0|<}!NNXB?9S zVExgLIOGN6XXdDmJV#-?kL9_m)fx^gT+zBkVG->k)_^xjqdCqdx|W=c&o1#_Sh!&C zW%8H$Yw}-})!C!#@j910sWd14G&E2|7I_P=oW!7lrQFx7U>K>=y0wH~cq&%YrzcyJI~ulfOegr4shwo9NStLg*1Sk*OYUlIZSLR)e=UV##Y#|j!QBfT(g8rPn|>5Def&#L=T#IKZHGc%hv@`_vz_#3 zNNwAWnvqcqoxqnA5MV*RBAID`fCPuUb})lx+ro#v1MTFCEE{LF6S43`wZ<&(MFWgD{NDY>;U)q2jt=JE}Uou{~PU0*LU)O=%8D}u(iXN9*Wq!QoPNUbS0zev5>eN zKa*p*ce=~C7_D>KQRGqR4RM`h>;9mC4KrSP^|c>`0LlQ@hM|-lTiWG>+U)|xNpj{u z!NMi~^r3Jr%zEqjB2`{z&Rlwd z5jICkBxL==CE=a~(DTQvC#!3XphKC$cvhNL>T{bB>QGIzLlF^;1id{8gs5@@$+JPf zYz3z{7@+)hyIeuvfKI3kf8;jhm{lf=+e_;}s`IM!j39=6O@Tl4&!3QZk9$=W6+=>1 z+{eX@$>F;(X?MApOgZ>2^T=@X{rty6^&EHLv3NXc`_W*TWrL)lKa(`sJ!>>?rMQP8 zo7fs&iCIpOn>z6`^T1t-10iFc%tL#U<(1AtRBoO~w!v_tnp@?O0w#xS_eo#|Jm-J8 zyIjH=)czpy89iiwdeal%*ke5MHR(EV;aW6W-4_V)PX6CVI^qhRTxXLbi;1Ysc4Ht^Gm-C;q3eqZYHK-8e*A>Z?Ka7n3hD1BLL zqDvnm#RR)9%bn5kZJh?+zVb-;752cNW21PF9 z+gHC*piI+b3_`2n4BecM;7&T@bA>$Wfvgx*>(Mp}%$1ep`h1;aRbG;1e@4)%KE{l$ zO{iK*No)+9Mm$L1WJ@Lyb2WLE76amcrLf329o@dgmgq7La;QwQmdvJ%GC_`CPgh$6 zs#MJE?2T4cdj#Cnf_)S5SU;g(HZCW(>NGIcx_t!;C2w80b1#y%@u~O~E2U}mbaDOu zd1>EU$L#D}&!bOZ>57&CQPB>Y?jczZ>5wv=MSnoGkiUf+-Jrz>L0C~}B) zJVToT+Ov%)HI88XwaRK12u4U8>RPDM(5Q#k44xLF2Ut@&r6=xqG?vNX{Y#tibLr@5 z6j;*}DwEhRyVr| zL?q6K$gv(e`-!MO7Y%YrV}o7`^tCW%sg!c}X(pb=HRJnGSVW)8ZJ+|&9g-r*!`E@J zW_eV-Z1!pEmuyMHo1U;%<{Web;f=7BZ$Wbba9L@r&re;SlY^@lcv{T9(r(j^l$v_m zvlWNLEh{w9b9B&{3A(o~f4Q~Jisl$$^LIY_+&CEwyFoPvyh%GZXrpRpyYn-MWGgzA z-zb$ctqh5`SLWE#Q}TB%h#vlW9Q%^Y<|0`*NX)gSP7QM^7YO2$slz|mBo!nW{2=<% zxLApZGl_)ORrI!}QgOG${tZ!w3>qK{!D`OKMaHA}b~lCeTZX{9ODhq7EoGLK(|t*0 z>xzQ!Etjl|LEz{&+Dv;^Mc;0&h|aG+j&6UW%*+K!@fnJhQ{YIu`^aze~fH{BU?n z(caJP70i}_xy<%#F@8p&>K7}E(qEX4-eEWVphUN_HlH4>mw=i|VQEKun$tot&xHLXmO((k| zT;w1qO73u&6J)S#D|!V`G0)tfJ(ahai8kx;e7~43l*bnOQk|Eb6Z_63SVzi+UC1kt z_*pbB1l>vKgAj`~xAF0uvSo5ky)e6r+jNkD4cc(h&hkbTR9|BZrTGGTK8;0UcD_%Y z_!N~ZLaOu5+LL~W(eU}suci8cb`Y~Cv&;wV%w15FwEDchH@l>6|8crC{hrj$MElwy z(Yu!hIrKSYsP)y@QXr=u`g6!36VIAf2Xfdha`BsfpV2gCMdxCr#sV#H4JuV)1)bP& z->~20fmF(El+qh2ypcL>ajHiD*w}aLRQ_%U3rasrGH)F`KcX&QCg9Dc+;>Gtuq+LFi_+jhi`-WL2;<&>QP4=wS5#TG08n?;4!Dx_gni7zqMBP|c~W?&orh zR4VbaQ@beQ@pZL9$nf#OxU|VIT~5Wy_Im8xrVL*^*OX6!AkAe7AOvGA5UJcZ0>;j> zie|IWKgL9K4^Lni*1w3NM3?|;&(G-lrH7T7i`20i8zBC`&*0TuX_`7g*8|vbR%;&_ zHfz86hOUS*+m@a|PO*o*TKao!W^uq@TU+@hNir_oU+Fb}4;Ju>xIhH*(Na8H7`Mq% zaJyx_^b(e=lKa?(WSmCvYcMBQB&p7Nz-18^xo5o!^{p_m8`U|y#Iq8ey`#WLzO|x8 zQ>S(=RLj6-2dx9ryc=0d$EX;D_d?EyGOGPJRZvv=yz0>(?*7E;=w43yE$KKOAJ&C& zOU0Rm`l1-3*x0G4E!vF061pjvxMwpGU)CyAH3~00aiLCw3I-@~4XsJSZy~O(<#BaXk4ye~cN13!(y_o|ueyq05j_+6{C60g;AAeSrTVqdR`lOJ6)w0 zFm?p3j~5=MxN)Gx`obMrdRdgox>00LYSNhE8@Y@vdtQ|vUp4(*jm??<@8#ZxfrP#% z+mTH7`3YRy6U&%IwWfV}C=kw4wZN|M=hf&DdU!T+D82d;qWK69UXT=c&ilTp;S^QH z!RFpme$5Y|&u1Q)n*nf)^4&vk z%g}$zvx-v}SDd2H=C+~p?$~5(#qv0S`T3TuJA+@1EH&;@xTbT@o%EwJPBl7S0Y=N6 z5B&}D!iwFZ;Jj&h&_XSrL>pg;_s30g{9;Kck??;25}^ue@!1EuzsCqk7D7CHIXM}= ztu^_Ng3+>B<8HF!jAZ1Z7KOAE16rLVDE}R0lp@izdzY%+xBFHd|4LA`$4i1r((1VT z``bE)Ta$V@T)V+);oqTC{EuSg%I#--rY#&ek74?c^LnSPIYVr?TX4Hqc&A!K;79lE z@t3NE3CtQxVPuXCn)*R{5RIzK=Q8hy2YX8ywD{NHYv_IBmp5}k*W%t3PN8=?#Ny|5 zKPU=o$LRs%C!rPc9RC3taAKe*3bVNZz^%snU+ZzV0#WGC2E^MH$ILa_d_wZ}DfjxZ zK$9tEZ|_z(&yvQThU;K{-$ZJ38K&!w7{zaN!;`Lv?L<*ouv>+fh`IiQRzynsn!b(Cf^+dQigm|DQb(cI z$=HQd$IN?Qx zcS46f(uM++roQ!h1-{I0O)*TS`*uKnpX-eiGa2-sSQwuBpMt=T)gX4ZCADc-vIJGz z@Zsvn9&r5T4flLQbGUr6=uSgI7vB0@VCY29Bo*j!K3Z=8u#%g6W;GGz+@@6MAEbSw z+Q0O^@c7d0)`4R>VA-~JFn+l{^)=I{5ZKMZAfFE-7-yZwzman9>t^FB<8 zXT!FBsz@2Xc>%VX%Yi!$V>w7Rj*sVS-tvU$p{(%e81XxWszXU@2TPkh(JDdZc6lsM zDtEM}%2wM(GbGpu+BjhxX4#6Oov}DmzU_Q9&sKJbW9f!A>)%tYb7-0ocia0sGsUO~ zwWPH>&Ro_JE*X7%)_US-9+X6eomT(0UAznznUS&K?>&Xl*pQ2!{KQ=3P3OSud_?KT zj`O&9arzx65~Fpd7oyo*)%spixol=q=zbK~VKFW9%$+6xM%kfYR&N6?I#VeP1+s4# zcX{hX&y&%h`LDQwAnYh-`nM+H=mVJfBnCgqCIxs^VDdUfwRC7;P z?fj#W%}Uv1RcAgUsOqs$cJioY0Vlt81N6-iKtHspg(bEnK&O1^`tz=vL43AU>y1M^ z??Ice@p6e?-&5pP+y2KS0%y>3z;yI1fU|ANx+qJE6^&Ntox{CMZ~qd`CCIH<6kb1Q z0!d}$gf?Ki?U^ZHrMLli#JdWngYXR$RqQ2-K0~RxicW#hO|&a{QiNRZ8m(GKG! zC>?HjqJ*TvKc+Iiu^nGWD2boZ7!O8dGZ3z%7<%kECBPy7$O#*mxs7GpdQ8~-p99Lu z?dFnSR|@Uv2Oj0LCa`?0LL&iU?=j&Tr%WsVr;jxkJx@I4--fNfx^yLd5c$~~hAY!R zuHfWP7Nc!-fo4$#3bpkL+ah~5b;k&%*vuE;|9eYS6SwzSH}QgMIi=Hfewn@aL4@|3 zMskyIy;k3CW@t}~YV{qzT5;ZCTE9lhTaAb}3&~pw(4HI5sf2BqE&3+Dwc8u?Kg66@ zXMu?`!#PZQ4B%1%{0)zQf>%tq6g5enCa;7GpE$^I7er+wHuNDL`B_P{X0KTUoAr09 zS^xyDgMsxOlsyURo`R<1sOgt4l+4x|g=|Zg8#iH=J^? z{Z3#nGJaN91}BM=uEf#&Uh<#|m(r0oDqi({t{d779#Oe6J{OSq)p6ZL_zFerKx<~w z5IeeZMTAV!Mp%QEP>!&_v8v8?q0hGZ0F7oJy;yqvWSYv?3z_T8OQsMQN-Y@ho=Gr! zbZ^mwwtqXM&fwt3g+Y!sO$4ZZOuwqnOj3ue=k_(8-Jx5aGo}jO!dP0ZRMk`b0jYpi zy=F?Ww%#mXoa!D=%SAE$xnV<{1^;79;)xK!cnbinI#=S+?DKAC^I_XS)Un^bT%n9} zwohWL0$L7q3FGeeCLy6WL^#5@vU}9`gU|-n1Qr+7LhFrM;!%j&@jUr#C`9sK{x)i# z<_>3H5uy5zQVnCiO`q%cZ_ATt`~NLbSomKO1@4l$jI3(x%CKRZ67)=wU7peEpHF|| z^byuJRux`y!xlY-lWE>%9%XMu3&x*Q$Zxs}Uaxy=B_1X46%;ZcEq_s}8?PI$mGd?_ zHW5c2r~+Iobj)y-Yf>Gb60?bb(5eu4{Ij|7`KQZg!z1TKQoWd6sg}uke=ftTn?GL! z$&S^lkcWfSb|i|ysR~$*(IusYfy!hFP@Q|Wl|{vo3+zmbT+<+^dMTe4m z8|AwaNZsqQFVdh%292RkL_7o15O9@TroF0)kN-To+HT1`B9RM!e32J91(&HBRa8=G z|HrJA)%ieO@!_5u$chkJbNY5WET>11TTwZ8ly7$pF!2DC@L(EPgqD_&VjMz%R9mb< zDK>xdF^gb)d*0;5pLv?8WOhf1ANJrj>O~4>-W1u>u8@s*V3tbww`GTVgE7)cVwXrPvYwJ!HDEB*05BhCdpJ{8}r@VSh#>E8M{7VW9vFj*RJ0QT%ylHMCr8&htCJ?yL=ZzfBVlBVMS$mRjA;(;SMXS={{fj;P z^-^_hG+}z14{#U=OYs!n601QuV;1rQ=+C&-JWPmG(YibT*411636R16YPzNvUvw%y zmqL$smJn~)Q{2}w5@2JSIEXqT_MNqfN6 zn9VU4$kIMMHZnOYH1t2Cp=j}n4~9`&7l%Zh99p9?gJKb*JaIB-WiN;<_NQ!8h|^I{#HHPek#JKzG4oL%;A@047iyI7bnQ zNk>LUf!0C4GLmi4{N>k=%Ax^mNY)GXBZTAL?`nDCu27q+lhD@2uSu^4kt=*d zVFS~cC$_3nGar~Z4ykR7D)Bm3{%#5D2q`Fa$hSo4B|@{g<^Nf!ael_6*%5MTnJt@d zAQtTEWXjTI^)-E!#Q{Lr=-{uAZ)Hi=^q1qJztwl!Ca>xBt&ve-q8&>i+D{|((*=%R zV*m%PBudM2{e%L1D?2`73*_twFz9LG&I%P9h-%=Z4B?<#ddfn@e<0U4p|gqyN-y-x zJY@c{QQ`?@Ij(2+EDw_}g|y?%#Oa^tYvclyyYS|6mvnI(Ra6Xn-KfTDn zv?N};p|H#zvW_efAECc>!ubdTdnBK4V87ud7gINmkslTv@Zx%<)ITSW3AFKB-bT9Z zm{es5nHb=~rCKvzp5>{555<=Zi106onR)ry1uU%;y0%}u(ZT0#q-W#n`1%xcfMs&|6+MwhXA29cOc zZB?|Vl~!bOb`{h6AiwW5sN+h(NoD;hySr*+Ch2|JPtvdu@i-~v+Q0^!#DVro`pJDd zCz2Y(U@$EqX*-n1lLu__dhjpj^hPpz+N@pe!dO2;-oa2ZfKDeGr&i|&612E4oQGP@ zT@cShrr95?Xe*VX@hgp#PpaYccIwj2mgOveVK1z~hpT1$>_xX$5zF=jIh@3=^H!(} z9_o9gKfiVF7I=leZhn%?uJC2vO}emlEVu$!F9cV$|Cq1b1C6cNThTF0`Bgd4Z436@ zQN@5Ojx%3gjH@OkdY1`$Y(0M5FgSjNy*srG(uqaX(Q%Kc9iuGpH+1Ra%4AKgxsM}O zF-z{dya_e}(YeTmIEgXa+caNADBVYH4LBGCC%9tp7^o%lOYdGKb7;;n`q3ptWp>B0 znm=E>vQ67noQeHlsKI=<@1KXfX+%MDyTWBu?m2BSPYno6xnYnrR)opj94a+;{=x#={n6;ImpoL>wsRww5WBe0UQXI1)9OP~#dv3?TxGienjR69{smJk8N?tR zHV83~(EXQhc=Gs~RN?!-iutG43(o%m(5C0Mrnf_9>Zcr04O20)H#v~b%0Jk)#ml== zBG23&IqJ}ef3=Ta;!U2(E@-YZ<ln=!j=OO>#!3JD% zWYU$9kz~4rxmU&5XMMvxzy0B+@_5zGPRx-uIF?o8a!lj(XRINWuTZ)WyB!>YCi2Uv zwsf+9hEk1BiHf$qPm8Uz?~@S@nfpAf!JMZuVQ<@ty9`#dWFJcCLXUV^&kS@tIqyZ6 zx!&YHj$*}T^&FXv*@O=~;15H3lxyEeAP#1f-HqtQzn^ah-9=j!y<3Sfa(?NMQ)m1#Ud`WAK06RmYp|1&d6}W`;Sb7Lk5#)K3(NF4)VoK>U z2q!;1UfnpFV^An91p#OCa--4Iq`F>c?y(_>!B+aL!LmEm0BiWzEp}LA?UOb|t$4lm zj3PCydeXrgW7W7PO6~wcxTe3(zup5-X~gG%)@Ktb+ASkZH#D@C$0l6fqtmx^&{I8> z9xK5>xs9B|o9*RzOhQ@D!OM!4ej$;mJ+c_Am4;TgY|@aqpMlFS1Cj21g>nSa^Vim= zye3k7qQcEd+5Hs@*$lWhEt{xTdejcWuIyKyD6Y|a%~T&ydc(*nyEb|2U2Q`v8lIop z6)*8V$zgAqZlI%D(I59tCjbhh{$RtQ@&RyZ|HhQZya1xD0KI~k1J)50;2+qcoaN5n z3)LeSZp$J0{9G+8w#6?xhCg0nj6AKrnz%ZfZOc(2G1^=}7pp*@R4JCrx0!EZ8eJ-~ zX2nl2` z!qO;5bdLA=)o17Sc_GUrZi|0b=F65)xH)MPAiIJuk>uA!7ja7Ja3eFeIUWnFO@vNw ze_tmY68$q2C@$2BjjzoeAmp3nB^NVGCG^pcf*?7U&h}-c*CJo#xT|KX2xRWc|sDNE`IY zLzZuf(6Q?O1>y~5%<(N2zcBHf9dnZ)Z@Z_=oot{zTiH)(1vgABvJ!8;USL(0Qg#?aFKms(uJS<6@$zEn=3w3`WTG^b6lqJE5`b6`y=9m< zMmEEVNHF?FV3z5G9vN75A4vyOjBTZ;Z33h%j>Yzt#F9k}7=&ssItE95a;7cag@OcOKbICLFwRTD+LpXuS+mabbfG%9EZdQD%=h*r9n6FAm70-H3^< z4NQ-D!mlNrAs=A~BBJPhMZA51fRTF{DgQ9Jq1P!}pAZgT1EiA_vBz;Dl9!H<0Hh7{ zhRI;|9}9%*&%1Nh2b4F8LP_U6Pof`Sa+%37PBod19{u@(pxY|=`^aU1^RB4kN|XY_ z+zYr=yU%Q4u(T|@ad%PSrgbQrmrRk`5hWPyM0}vM3ZkH-w|rZ>JxX zx*S@dx7g{CHZ~JS5q)mO2nZg<7&G`foU&&w%Y8k;(vl`Iq*kVO8@y(v*-T9s+WzsO z9v@hXT1flQCgR2c^6S=khQU;yxfAD&?D0!yagmdgkEuj|atK+xx%*swo*pD130-x= z>)*t_t~-KT*cU2b781M$T@D@TErVV!NKEaABJ#!8%y5%ewya8v?WOuS#wwo^%IWA zu*00%37;c2ezszCoW{pNIUbe~l|rn)Q?>{SRqdW6NVi-MlXw7nj_pk3(COA!TIG`! z8Se7@MzwXNKQ-CPQa9aZdzK=E;!lmsxh#PzpN|FUXkw~l?C_J{Q7~m9=0%$Q@Ks)E z{`Pu}n&JWy3qNHD@$r5r>l-P|_CyP#Jyy(s=r~aL!B8{t#B)U=EvMMytP*gSeT$Gt z;WP*q$7wOy{+qQ%9ON>>fh-OL{s8!!lso&ROH?MBCsSFXM|h+;oc5S>Gn%i;TK1Sc z#lS_Y^LUEJp;0-E)980hA@tc^$*f#SwV!N$SuUnAGWqo%)9#TWN%s$f4u4h%>3y3i z&t-|yt!yQMv4s|?M4}vfX9`K1Zo(6&3iV%g*ei!~Omn_eWcR)Ifoa4Nlqm-0Mx^_? zacR?85`7UE-nle=<@s{J#~*k|tQOTYccy$UkMoq7{5eAsqJ*K3=|ire(Q3#-V8K7T z#0Aam*g3MQ^f)FlmDI`|*ByO8HdaD2qePYI~)y?b)6qJYgktYN;B&Bh^kp1=8 z!2ZUZ!BWn=f50m%--hH5cVN+xou@8VY(HTALtRhPx1u?sfuDL`A9iA7(bBZ07?EZa z#h_~>uTlhuCz~i#h?~Z>P*5BtlT+RB5 zt$&oTX^#x5^UCTB1;sym+Par4RoWY;1pgU<)G8VI&*^g+Wc-+>!|M35Z=*SWfMJKW zQFM|0l`Z%Jo;D>wVQFPvNdGaehnYf>`Nh@KS)Ks=%;=00X*kMrKM<2tLM*oEkia^93VL^G)IP{kj+-?5ji z;fXUO^@Up-grvH=v5}T(nSAK#B4u^Jwjhtx=f*yPXqS6*3M2P4L>dlFYZ6vSI%GM@ z2qx&}SuF7Dg?E0AG=cnRU6nP?rz>?gr*NG3&ii~$AL<VHzUth*9$l(0 z9{IAo(-KK^_fAXkV;o+G(WuZSMcDTs4DI4p>FW*iz#1OExw<>yQ*qtTqbQcyeI1+T z<1jU7eG`mW?B>&C){~C^ZI%Yg^J(!=)L7CKWM38$@EBN%*R2WbL49t>7m!!h)rha^WV41rO2Uo?kzV zkfwil^iXAqws`hNV0zjCQXi3lixvnquz(RS0BACU!<{R;ulo5X_6i|-$1|S-Itdv7 zVR)a<>GxNcHhq`Y7GPo5jjp;AaimV?w8UQTGiE`sezWGbyGkA%sLsYU37S!$g4+1V z=eZ9o#bRM)uQ}@!=Sba%=N{7;NEq_`a6xm_lYeu*Rjv|j6vM79m9%VYIGuD2r(7ik zW|>sIu|{}=>_}9X)etAPeDbdXD#}4OU8j;Pbos_f3vzJj7(8A zdB(gI(=9Z*|3;KPbuS~=c_aZ($=SFGXH0ir3(iEQuA}#2skY&*rB+U`e*B|)a?5FV z8xHfTM81nrr`JrDBpQQHYkadIWaf_|ac@5F2d$izQSF8%+GHzn-T5?68Oy4W2M9ZQ(7LXvk%6>aa`p|j9dS*f(_ij|c(N0ZO(b0=ll4ulE!21DlA{U{) zh?}e)zf~-;){GgL!=6sq)cxW4jF(XJHN(Rf8NkU;&nWCfy2KL7NmIs|d5KJN24=Sh zgF{Hzw22ygcbT021H^pz<>hcZ0tyLTlPlD#9UAfBg5b)Szvp)tRCZ zn`o%=ov2~JB3gFK#H3VKD9wYsnBRZs5%Ks_mGn@aOr}(F?m6}VGix(Ls_Gs0pONN0 z`Yb;so|e^$nUiVD>YjfL3Hl2d&%*=I<*~>esq-%vWHq4Zg+{}~&8OWpH@)?iKH9C=dI{)Ii4mbaC?&K}jGhcBaRGLAk$n8urF!4C2%cy=9)Q^)Yge$@?|=<1}qDG(>b6Y%4Ge8=+~m6vPZmFB8$Sa z*K9J;?-FhxflL+5>MqrM0F_5GiQ;4L7{rTiQsBkZL`pwJo6uI6RE;ml1mTQ`USX7@ z|Jb)iXNW-KR3bkN@cwZktNanrZ-8l*G2IkZVW3>;^Z&zRpzH_t^dTd=QJ83Ax`xv<+Aq4R3G(?9D z<03UqsfB2Q?6=v36+mwf9Dq94yP3Fc*=NPxtQ}wFQzr5`ThTB-YzGr;4G5_-huOav zVK$SB2&Kv{fAPr|Zz%3#lv)?2&s2%e*PsV!&pqU(wSymvR6l7riv$z-S7W{0jpOFI z7axkmKkzz0C({8@nuj2uAo8}7}`#`q+jFvJ@6Hyeph}T8F_bk^>oG26s&0rZ;|rI zrjQ{-H;ZzU{znLqb=mNsFYs5HoFM95M-;W4ou|J}J;D+|-i|LJ)JqPdDT5FXDze?G zAK^r^X;0Nob-S9eKM}xfPI2A@4`yYD!&A{nIn58yiHEp9{+ON~IoVBnQgLA7a}|y) z0PMNIB7ztaZjJiGOz)HnHXv9$=A6Eg{({Xv#4l^cboxIf5%$JdGae72P5Wc#8sdvv zg$YBe%Q}5^uBe3BraYP^u;!Fv?UT%RSYAHOaQX+r4UT!v3f9Ryqvfx<+MGN=sj4`c z_w&jmT0>5oY7o1#~}o$R(skPfh~m}<_Qw7s>-R{ zR1k4+)o7Fv2=d=!2W6=+b73fwG4xQXVG+USa;jftxhCg0{NeYhBTE4qgmL8rZ%z0s zev>(26r3#*EU42i%@z(?Ql#2VD5x=lmG3<#z=7APslROJL8b5Es-_6>K41>yK7s;rwB}TRrhI*>B*!ygM)J1OqRWhZ9YnGBs3FTAK zV8VHMzUdO!cDse)29jsjl8gDh*~OUFW5VK?Hqt{bu`7SBu^=DgIrCnZ1FlDdu+ir9 z*yYpq(c^3M@jCBCI^d>^-Vk`AAD-SztT|sglC`Yr{F8r4la5Ly{6WQmski+=h2xeV z&)ejTLzK(o3wWob*8#9c5mQlG#nR_V9opV7G3|HLV;=l8jx+4$aN`_dm(^YWK+x}D|h3#Y*jRGYK?jeeJTxpNiP`@9iEDX2|bx`Le&#ff?n2r)nl%q=jI{^a(X_CwnI|MYp({*KAHbDOb^_o*F?iT zFYJ)<5};aPl-{rTa!D>vcxNLjb*t^`Q~?O~+eb@j`y;svmXn-7&BjJYbT~z~i->gg z(@%pu#U+2+^xT@FInqBi&OzUQV3He3zN83`X@ziWOxD$u`7LBXx5gdrfSx3EY@`cX z=m+A7qh*uR+_*yyB}yN&s)OIy2ukX|H)&O)5#+Gy*bFE1)_G&K#=UvC@QoDh=6XQ( zU>1k&lcE2~oWVq2*;ZxdQbxaXHTNl%pR=l(ruaX+Yh>4eYqwvJ28d!-?~nL`j_O@o z|BFiY=_eQ0S~JD(_xOE(_|wDZ$miSMkW+nX(@psw;1+=Y7XFtkg==)hI#lp+8^dG3 zAna^~S-z@faXiDO%1w}aczyYW*#(HAPkg8Q&avs+hK6y?TT7HClB8O51bM(zTB4&3x`;LdHAhDt#$zb^O ztu!X%iZ7jEKUHu%Tcm>|6DsGIXLyTpJLIqKr($1v@DPUXD&2}DYkD}voxcGkMK?v0 zDQt`15IZ^Kt~Txa4&j53C_WBcNgheZW?j zA;w%+ANi^Sg=H}Z?(*NoiR1wa+QE57?(?4&3KbK8#exBXO8paKkub zqPrjabci;GaEy#CyWAyJ2e@zg&soxu7$s!?%F9SUA^iN*GNfF|Ll=c&s|}Ltbt|EPA2| z8EicJYPZanTv#eoSE4@*g3sM1yW?A*~!6gR7lm~2i}IJ z%M7nkg6A~h#)`GAD??GQzE_Ax1-pBT`h49j7P;x~#x7{UI3asj)}HFEw&qm`ED*t3 za-(r#x9crMJe*?EN0T#nY#y{0qc$c23!Uen3%$93`lB_*BJ$%yb5YGivJ6dkB)+v9 zI&LS}UmPQN_yjxe`THE+!7ou&G%}XsR6f6Dz`Gp0?d`-@%kK7PAU=1T&6KPv28X*8 z43_g-Y7ytE!jH}sb^iws6nx$MPNzV~qdFuaG(y2MI6 z_)I~;EO;>Y`%APS%apU#>|5tD392-LP2ogLzLd+b4t6}mNqc-L0O-@F>$uQbd7a%BY4^Ny3}CtRetKYKoen{=zh1LV_uBo^vlMT_0&5PuQoT49g5t#z(&q z3#sLG1hj9{uWOSMACC@gE=H3fNV!Y*8Zq@q2DPX&ps3xBf0L(+>>=$YEVuB}UCxv8nUX0GLEd6DVGd@EIFRiYYzWo+ZT+~4-n%uq9wk=zI@t0O2+4%FHpY(XXuJ0y{ zH1@@^+^*k!N|{7UbtR6I$!+ZEiOJHcE!~lBq`j-uaI|%DGS=NUa=4;~DfE`AA+}f6 zTlXyy&`sr{TAY;R*rqLu;!^$W#+iAX+8v^V{1ldNdgaY0(n<#-l&ah##jX^)vqQJ# zzF;kt4Cb%xzE{oN%Ho2V^OWBjCBf*#PXtU~@b+Fe)?S@VI7H4+QQ0U8S8HB;fAE%o zE(GWC@%*9|+~~?-SBX6f%8<5PrAQE?iBh9P8jwSao|l)IwRj3d!IlZjQnw$~Q~IBYv~7MQytg^-IA-SJ5Vfd7$>?bjtMm7ek210 zm#|G69f>AvdEjHm8qY0o(;)Vf6&1W{jBCBbp4?T_^ZyE+QkPFi#rm6Wq>}PArq|NS zj^V@lJN60et8-embrdh?tZm(vI!^R)mT--5jy{jeB@bo)UV9;}&k)EPbwcnTKsO2W zooHXhUr3?4;M&Z4*%KW>i|H=hbVp7>%V1Q=ZR}mkMZ9EEx|MeRF^Wr8`)%2bvL3p$ zlB6f%;TENM!Ga5Jm2}Eey=lw@WI2wkD0#xNH-7~Y=zvep;C#cBsZA3x6bAb+p@4l* zR>;+%!s1b>AwKOF+@Z^D0C^~;QT?`*KUb}LOF-X1HM#+Q07lM3$7N5g4GBJBsaZT; z_U!bUp5Gpqj8w8FfMVM-q9^w&W(rzQlNOc)o-p|ID?kS~38h$UxzZ@@Mz~w{qi(tm z8=rU}A0H6q#knSNuCRf0QOYT`6r=k4rdwP$SWqvJEj=#!)NgnU{h4g>fo8~?_QTB{ z3!8Oq_KwzX&hyyD)H_ z{whv3-`Y>*wmfBpr>W}Y`b6%9rM)_JA`STxy+91bALi-BIT*>Z{^raX{CUrgMo!h_ zR1cn+9;!OS1*2jas! z`=N66n5waUrMSDO(?q5k91Lr>H?cWz$g*yS*-$LH-$3p2`5#9~-^?aGUDf9{?L#dR zsSA$=G)#h3k}oR(kebGJo0W}2s`Mt9eU*rY8O1d=7>O}HMRAsy)w+67F0ZTp zEOj>o+C@$og-_b#I;~!l;{(ft(>$@mzlR^)i+ZK*l1YAVCV95OSXa_}?&0KHkh}QY zA*F%By|ch72b^Ui7b$hRLEVzpIqf|FvLq`4O%Cp9vTiH@&BDMVz$Uq6v*iy|kB=Fq ziII$L#~pe!U*IjsAwz>xLqE6nZwCNFCeb@`O1lG|BQmvv!5d879tx#o;}Aml(dDlF zbfN$q37$8u7GdgHSRc@bE_fBQ3OVav_Sd$JdM-RNM?FGV^cmL+qV$;&=k?F5e@Cfki$EOLW0$bBY3^7Ye1?4S+Y|#ql?V;Y>AY1YFbfKom>T=grZ8#Mg#W}WN&Saz)>o1>=<;ipb zDXCT07(7#fjx80l_&WI{0(`%U*G&Qso~zndl_Yy5#8~n?cp~I`4nO-aI5nx-x@6y_ zs2VfJtK0NiD&@heF&TSuM32~JyRKXl1J@>sdN+Mh*F+Ei0VBziB6uwQJ4ycA>4sFk zS51BY==Ee(zct2vuC<*b#VseAL5emv)L-Af7E;%dSoDS@SSlKYN#!|KW=70h)o=R< zs4kj>yY1gXbh~qFbHa(D!M;PwO_dv(6-lQOP}4f$Q{6QBQ*lg}804M^MRR$gkG&v_YI2!z5>|5dU~I2fM9zqZl3QW3>SX z(_ZDLig7PKc9?Xh&T^L_#DYRDe7jMB_AtZtu}MA28{eKF%&nmBJUe%{2$Xu{Ef zPq7e~<~CWo6crib0_K53<5F-X`KBIMx`<;bfHvCK2Smj0CgOTzBFu-2tAoZNo#EHH zBBK$+4e_nwTBkoBn8oev5IyT-Cq=`l2|L#nWRisQyY(U&lS|6Ex-JwP(pY+2m~f+ zRkMSGp9vjqYvZw$siaiA&FNoAU-fi%azs0HQ%%@Uv>r#`0tvGxq8rK2jc$~%z2M2L zPv%8XwRdt9w7qinW}36<(*hUiqQgD#8H;O9E(K5kL}Wl1Phw%tAAXN^97c>;&B?_f zl_bdjy7+P!EoPkWSc&3Hkz;JP2u)do&P&(qYWnS|r*j&oV(s(f%kM`tZF_fC5QYuC zmF1Hx&Gna39650MOks^kQTIX#ZiXwRh989C=PJ#|2m`Dhkh_|$FkHcr7%6Fb8@4}a$^cciFNY|y13ymeT zXrETt$-5fL2p?3I28|m&>*g<&03?y~jqv+gy=YG?ta9~juG6>vRKp89;+%d%)hbtUBaQV z;?Vawi~-tsFh#C^dqfGjj$bm%)w53BiAeX$uu?S`)E1kzBB59mTSN@|HUtaSYT3dr z+he`mWQ?p0fqpEIa*5%wi(4U!W`aO}I~RO*weg*I=TqYYW@~!MUQIxl#AtZs)_B*p z)m4@Sci=0B-&=`4EZ%wzag!6HjDY1jPgy)HOA~zcnsfbo9v>vGXlT51^fXw$L8zb# z=Nw}4IWjJTL9lXhQ|JG!_OkfDL^Wd6_ljt{N#<$}@}JmrBc&V09sZ8Dga#WmPOvp= z6tnHz+p0O}2CMY8jNe`+l-~vBIxQy>80B@>()8N4U%!Bz(k`v5^djnS9PW9(e93gS zxLET{-qpQ37CJT$ua(z23CdAF2m91cpPQy2D@ki4O)!p6g3&-pNP)VbG^RadVv)P1 zy*6av#ReD#wPvDROzG_SN!dbBw6@`|0N}WV5|nP4qQe+YSV&vs@MveLLcc0xsjRQh z-9pb*z`Y&)s#IoF2H#X{I29bgH+1KUF&pD{0roG6N&EXt85KbK34KUz>{%OT^fvhO z?(=;zSZz6sTpWOVY=ZZiAVI6xn7|-F$%*!ct)P|(9j?=x#>Ll+tLF>gF248{mfk1= z!@*fMqsim`+eYWpo>hV+=lE@Pl@p)EWg~v?g!2b{6RtWrxX#y?sG*g9*N0A=IFxG= zI$AWLENg7f&8isNc0<&Vd;`}f74m8k%SPilVk;w<8omz2Qkd+8FFV7RG7uCQDp8sh zbXTG@&>acvJ!S7+dd}Z=87L_jf*FcO^>T8kdVELSq?&M3Qt@IP1Ll#i-j<25FN+(> z@0=7u_kkB5f)GpD8T1(c99t!eC-T)6Tg#2 za>XcOR^y!)lO`k^NOg~<$5fbJlQ%XBhR{g;TFEaqao!#Ev9-j)Fn0nwE^WP~tx}jT z$l`@{}GcT6&@CB#8rMGeef&%5|)wvGwuan#Kum z`_0+6HIo5Br&PB9%XE~4nW)UJlGs|BU;tHBM^d*tc+2?7vir%{+W5%s81a(3HqFpW zuLHMew~Jq4M@d(=|IJL(HnnzpT`}HloWrag1g!H++yk8lH0I7LzP-HU6!0;9!MON% zWX+@8sK$cRo27D9B%V5%RH^mp*foAC7qKry!p<+0qTvULcV+_TNC;u40jHc1AjusF zcMznXO8%@XVdw+Scs04NSgMv8l0{WFVdU404&qmaic@Sy<}0d3gk?@N^FUoL~ixRBqdv z@~OLCJTJc5V~>41GV0>qxT2k&zNPW)>nFBB0qP}TYd_sOjb%afKjidG66KTXnG6?V zpd)JXpeJB*9&zI%*R+0eh`hE1xxbrBsN7~>G@alY;ByRP$NB#C#f?WRwSQ3M8$^`jyIp8Bfe zZo8xtRcN|&_cT#c+gx{7 zk1wE(HP?@X7TS+ddAUWq5uCh=at_=t5=$&J{@fNRBYRQ{#u3r>oaQ6u(c6%|lKjZp zg~wkja$WfEHIih;pb?szZOa-D*o+gmt?XJ@FX2wNf~q-e83{=EU>4!q#OAyAcK`3f+u(H%XVar?wT{FGwqlmPAJjM&^ zbVS_#^LQ&qH3@&;34>gwq1+VolVy!o3*%J#=G8#DQ*snZIqA%ILxi}|KMqE0e!Rn9 zd0@SNRE=J%Rf$~BOp&I~DKhnYmi%hn#_HA+?HwIMYd}sIh_*ACx|;1>{2L~t5Pdm@ z;LUVl0hkBm#0@_rxQXDwRH!o?) zb(|BSV?vytXkQ)wGmr42Y3+&K<`xZ3b~O_V2EKCZyJDQQUr}uDro~Kodn@e-jrqXr zuVSlE=&z3D#IOYj9ogEyWAUm0z!`!-zFiqNLCcp;?1w`!J(-^*F2RaAZfMsO#)KY9 z1lVXF2Rv z&vejqm}6T^4{8m<>9niSbwCWs347Tb+m7z2*znx6w9ba{qSgw2HxKBIgZOPykt1fP4{)>~3f+CLN(HNYbD@`1m41e_b?)k3e26+_8=Yq+``t3J7(p+(j9$w$E%?r#x} zw)9LCFPix?K1|ed`Siud{bC9dr6868TJo{AtQS=h!S(TX z_?2|B7bG7uCb0XaSiF4B+7LZMC^}mY>=G+p!QeVY5-f_(T;$mClC+Ka<&S~V6hM=g zqCgf2#yQ*9pKk@{3qUxgn6$~c(wi>QM@a_X+%$rm)uuSlRF8cd;fT8K24O}E9K)Vp z*8ZD!`2Pre>$fdzitWAxUeT41P!tfh_OwF>nAet$gnRm1>XEE$`k#GY(*;n_!aFKvxBN61zBFPee;H3P#MRPakB4-?O6NJyMrB#6 zDU7|vxM8)3IZ6zM*BuvBZ-wxUIi;PuFYNwR6Wu{SEXCq5{m5ruMEYXPUdgnp5?HQn z7{8r&R1DcutDvB1wa7F&F)DER^JqEdiwtU%H9w2CtC5t*X=40lKIb{g%9WPdl8p%ik_4}^PNM}}B4*=~T;!1rsR&L*}F|K-0 z`{{|Loky!#0Fr^M;PU;TP1fEY{ujQN>d+xeKgr#M>;14-`^TNUO)NdCU17_ZiLoqF2eVnNBoR6Osb8f)SEGe?eyzXoTnRO9(E?r=PDjw#G( zHwDad@UEdph6I5$Q=tFu3A`o+#`C$}(K89$XkCt(!#b_iERQiuJLi9$3DM_e?^26> z*U_E*P}F#1{qUkKDTou_;zKKDHc+gbpW~XYl+|R*sO1 zz;eEj7CC*<)e9FP!rqp7u2yg<37P~eAGj#?-0;|`$9~J4ThoYm`n<0SW2Et3OO2T) zS*7-bG9oA`9XpEg$SskmrH2GtvFKU!^m_P1@?~|o=<<1d$NG=;4?X*ex%QqP#gyjn z)FAyrxi(PTlY~k2d~87J@j+{ z8LcWn+#LkrF-oYlRtJ&f`3++$>PkJjDcy2xbXTGcZAuzAwIgViZ4)x)F84}xLQU~m zh+En5m5eqcS3uc)o{wVKjE-kuYG7QfV}}ee;@1zwBm+g3wLtNxAf!UKtrA}-2|x?S z@)TTw698v*)V*|ve`0f^&BKrT_mWpdC+k_Q=kz)On16$c}L?M7#q%RqBeQ}5#j?)wvT#~MjedjR~ z3hHW^7Fh-Q+|1EBqB-u2yzjMGbgQ)R2D($Pkk7()1&?Ig#Kpv^{Vd>8oLV2wl+J1A zftjq_7m4f#J&683p0aZ1022A{;y|=*=phKWHs_FRX{n`gK|ZgeQC>e@gP8Tph-$#6 zw-hZ6A>X*~BU3Gye2x-p|$GTy)WMIAgO%Hlvmi;Y7Na8+OYH(mIuO*+mD z%eheSw%C$!$cwFrwdVLZQ+IhK@k#;Skrf{~%=#4UF9>U@A>pKs7mkWrn!E$)SQ7nO zr)%_$O`EXb@oBc{Aon&5V5q(`((6l^cn%g-FYGc+K6b;}@j>p#DRm@qF?M-R>w1Gk z(kGoRCqvv%V(&7n26BS-3Egpu?vFK|!p#G9o4*QW(5yY($+avgkj;;2M1Mc83mK4t zzI|9E=J{4?RBlww->QIO<@h<$Ip2KdXEWJJlarHZv>$iwgCXMA+TNQd{KZz~1;Uo3 zCtb^L-FrECFnc84O2O!T|iaD?9`|G6S0p*6+R{G$f;qfrFT5w5t?{p7Fnz9eu|pWRJT zg`F>ntrz6u2lHXG%6OXeJ^Es-b*Ucc%}Lc|(0vGs5|^kjgr=%o@Cabbyk=jk3Y84x zVA%K5*0N?2>KWqH?|A!ET@oCwEzY0FG*Ws*n7Ljr@O&qbxzrJfU(NmhR*oO+*P0Dr2No|Pnz*Gn<N~@p)P}^{g8B#VK&1I(5VnZu!)bl)2~Qhlc@zI< zLECRLu7E@?W&dwj%*=0kD3+N>>ivRyi z2~FX@rT-D_T8%DR$>XsOD8S4Dm6PNv3wB3WoJR(BEIW z6N&?CAe$UlQ{=^$# z!sus^2UAHOJSX28rd!!7-?)JMF}eA}hq&mv%FMt#N9A5z1eBzFa6s~I^2&lZ8Z4kKyTgC>JhT)iv(`hDfGqV4k>sOd8guSLbZ>l(0&&z}`qGb3q%Gx_di= zSq4>e9;%~sQy9IH+Ks0yV3aiQA3R7QbHEIUm5_g9N`dOWd&9^s0P!#y<<*Z*L%hy$ z11g(St*vrNRtHKjfjrxmWg6XT?0Zdo&+R8EY35Xz9_53t;bHMp;k78r1f!)^5zo&` zlJ3FPc{ZY*lBOtj0zt6tKgQ+kPD+z6O|JFo?6C$)_cwL!6^pRzrjP`6E>(%88L^FRdOMy-I7< zY!28B_r>ZfM%N#|7|~QF&Gh4*25t6?rc=qgcJW$EY(ZP67VKJ@jiAAF?`p<{di+dO*a1IkCIRm zj}cWXEAHjtd|*vGm1R?A^3DhQYodcKnBILdizc0ow`rpwOj@3)te8WCGn$g`cV03rGXf|MsPU-Fm zNU1QoJ0+w>2?)}NfW!z9DM0~=AuTBgBKm)MKf(Kch39^b<9?ps^}Eh<8(Z@G#~Y`9 zWgL|0`6w-=dz^R0cEn&0%GYvJkBv_?e?3}zdvmO@u<%W%uM)dhPI$?jp>CO^qr95x zZf%@#$9zEHH_Z{^6FRoxH32>s+1+oEtzVuKy#zjG)C!S@Hd@!&&6qVGZ_=^^0e&uY zwYhz|iG*}>R zlVw%Zry$FFWRoND8$|&RagXFH0!VVNyyT2`%Xo`_s^kQ?w6@rJwjvbsEt;G4zS7#R zOF1m_wy$C4UOnIHn=k2#Xqnb=kmq#qf(+-2r>OnNOop(P>XSLq?S59`ool`W&YC4A z?bf9nuFpbycTI+OIVIy9%~>>qj^vZ&luosOeMk+(z)E2jeZ@?*#N?rJp1g zVaX2L@qs&#&!4wp|GYcJ1(fVF<#-A)_eWU_%m}7#76+$*Jg{!JoFoR5n4 zW>0^^@OUV}8qMV0ollx6YD7Jvm;saqXFsh&^*=WtKD3=)*C6_7l$jkWrGwh<(wQ%l zuv+1#cr!1DUwmP1ob#YU2#~Pjr%6`UP;lI zp$j=(i@;s!q_s~B9wlvETnayGE7G_#q)oe>#nqeG)CQ^1dx@Xy#sxW3 zmIZlqc&##;T^E*cC3V0wTV}AuH?sTkFIiGedh$t3wO|_Az{|Oeh}h6BLJeW6%tjJc zx&}&GZsUR`N(yG3FfW=AP=<1R-gg2#d5Njqd|49wOzKU3Q_o_0#7pysY5yw!U(2m1 zeutCWRGy_hNJRrKd^(G)pBi%!g#enBz~a1BIx|gXqZ*_%ziFE9X>X#=d0t8aDCkId zCn}o(^v(9(Rd}Ot##A1Oo!QnD1Hb%$tj!3g$8|af(}Xophl&X_ycX#Gb^UH{g~q2!tkL^K1jwS# zfdeMJ{XJjJ{0N^W|9vUDii?NB>NOFH1j;X@8-V+~op$!A7d2UbTp4~$i_X9gg8Psi zjZCXm)o|MYc&v7$abi7;ho0!YSP>1Nd*tptVL*7E1r)60zBG`3JRFQ?Y(1nzsbOEH z>Bz8ljH|cUANN(8ap{6Yo+lbq`KnyRBUQU_UGc*QQWl7sG$ThaCiz-jr1KxoD-yPp zp7OW%2ZR`^nodjmjOTmip?e;cAM4safRzd+7X!5^^Xor8N3YymEl9nJ4I^%=cs{G~jsV{;u+eJZ@J~$WBm25x3!wUk^ z0!Rdw8E#5|BI=Fn>RMic6fS8X+_b5*Zf%I`E|k@b%z*<&q_iZ~(CZ7coce{Qz5!v|msBo5DDPzhq% zUqmB1gk0azQrLB~CydmGJs}l$WDD`NjI92?_>(jGe^6{tju8Al-sSB4hD||vl|b}B zp9!?_S#^81GA%B}yLm#nA!;2L$6V8{ia|fu5l^Eqlue~^?#A@iA>89s<<}Iy4a1`Sbo3)(_dJ^xLlEFuW21pw9Ye*&V zd#eTasM#9H#J4lmX5*#aLzMY5ho^cZrBysSTt<4e3ro4iX$s!s`-Swb7zIxE^>aQo zNectcr6FPQ+DyymqRo2buT13YGLLP=itGuz<#8-azvPndq+59UKBuKwQ=q!kxF3dA zVEMBOULmi7-la$SkIQtrl)#qhz*Ft-GJ29(?3UB_pBeX?)nrN&OE$|EJSjhomXNN@ zq(+|^Fl>L8KPo;*7iuq-dCo-JOeqEU4-h4B{)+v4G$m_k)Z9rZfiF7M2%avbT_T#$a+X5@$6$Ii(5XXFcC(n(QcDjHyzacgOLib_T! zD|Qw;SXs~V1(Pru6Y!A!uHJ{9(a&G=M|8>8_uJeXqz2N|2zDjZWToU#N0hXN{_N}M zK3E~0Kfx~GIZeuEQuB8ZmEf+L!L6OU8i|LmTzQRfAEg06<#IVJ`rQ?8&u;>p>Fpi$ zl@~}&m*?`!4JWtwR#p&h%be1AYE97UUwk(4RUm6&uem8{x$bI;DfIB&gU9 zy7iM?5h_lWXr+z9t4%q5A?Plc7^Oq1c=gfs0EgdK`^;P``6FSLZ<*DE*a<4VO*g=b;3zFwI%7&q98Bx!+~SVA zd#HWqIT{$=LcON(4bwce*@0>tiPyh87i zFW74;m(CY5R7ZLTc&0*`;%9!P>T_yV>K*IBRr&*#1IiCJFLceaM%C!r-BGSPpN^ep zR_|1bqo#TrT}|h#k;3)@BPe)jF;K||bY}81Ku*O>!85-=#=K#PI?yvmQd?Ew38(2J z=K^~07hv4K^UmAivzo_&Bh$}0$F6dz24B4bL`M|w;Lh)JM|_U@i?M-!M{*Ki9|7Lv z3qs%s{fhgEkLrS^4FSR&}q#moj4fXyiA+2WmqNS2melcD6=&ZQ9a9a&qd(qa#jrb=_J; z!obLB!g3D2H5u9M{4~OJ|JdsC!)n3(z$g6xpIPA zD4cg3@3+xCgyE$^^p0&-Y4~NDl^!}g zr18zFX1)kM)6!vp+_Lh~U=~5Q*N|1Rf@=`)0ktr=7dWeV9G znbFaLgBq+aJSNti{eV1)t8;-Yvh4uZ`+tzkgVXx`>_P`@&;)9 zlS$r1vy7&pAKfO=rjM!FA#)2CEBPOZX-Kx?E$sQ&UPM`1O(ds|4DRHW1M$77C?iU( zZ5M5xF3h-ae7H^1w_$i#l#5Z@`>YkuSsd69aWFGGP-E-~AQ&@X2Q} zjD38_Hd~6&3YoH-E^ycMfWRkwFX>;j9amEoJoGKp*3*Hi^VTinE7d8}{Q86{S2vB# zO=G9Z--FPXPW+pV^r`a{8Ha8miEJvX9ReAN_t*^;ZZy=m?Gb;{IAxJNeH>xR;K}Ya^qG|yDE&hK3AjLJ>45oX7FNxGS z#=Sk}($@639r($Tl3wqeS9yrWiWBV}I7#$jvQ}Z_-BLV0OZ}k}xueFnbgtR3rMnS} zepCK|Nl+Fi$%@_3P=lfRxT^4CZ_)W=gmd8!`XMF>e1Qup9@}@GKhh4rN}snfQYFy$ zqnj>-?6V&IyDlx<@aq$`mK2zVa<9Kzizdm`Z_S5-j)+m)?W}9EmbM?T=7K&5{o*`U zJ8LWs_{K_qoa_8GEOD+=;ghxIgEGkx%H!PD0{du<8+59e-Hna>Fgp^x$QI6=w$arc za`CI})6486fSdisoj1Q7VxH=hs5Z%xs@{nnfAq0sw8-sHemPEthvA6CzzeGF&PUX;KlXx>MPc1m zKcrHW4dTmt;1`-3_P2X^iJ7^SO;q|{$_yIh;l=137N)-+R^kB`+Bgk;KKf~ zPWkc=5B7@WgT1f*yQ6bJXawC31mq1eyQ)wEIS56u|+7KM?W z(vjESM}6C~tBtGuh%4|0GhEBlD2UKO&-n7@|AObm@rZ-sqHJAU_J_htnr@uSW_^Cc zWap<3{G?Wq)ux8N4ZShiUMjy$R%)t+W?URe6?og?lK8&HY!NJZ{IR7Np1(LN(;s$N}LPx%<346mxlyt~f!0T)s46+_GzQgCh>U1{`RGjAdD`aK_-7k*G^Z_0O z?V~U1^JBv5N_uTB+&x9EHy$hig3;t{4@Exg|3&OCVNT-Rb^sw2bz#xe)EhIE>q96Eq==Tik<44Pi;dgcSH5CUplEju=VoJ3!B+Y>= z>+IbARPqhmr;R<25|6dM=shCU`Pial|0V5lsn;)sXPy^Jkb4%pRLAw3;wFLM}#?4hDLO61KJbR z!Fx=-ux5*54#3HFv$>@fY8Wr4A!g}XpR83u5*3&~3fqretxd66}d?>s`uXG|`g zK+?I))?Sw)8Y=Uea3Y64 z{%q;N4FxU-6)CPv@ox?+kyY!4(SE~hZVnzklkI}B2Z{DpAA~93aHW}3e;WCBk7PGbR-uRa0 zTSVFsR%C_{{*fYTty745=gVU4fzF9YTVEUU-3a;F(l*5ulPCJ+OmdTZ?_MSRf3+bW z30#%BaHF;ERy|N7lBrfV_&oXc0j_4W(`j#ZShVS8$bnz{^HCu7F$eC{pk)aUa4s6J zIj6O|cm@7vAt@beo+tLIqfvv^ADx-Q8fats5xaneBz}0R@bEFJxS4N3%H<6qzjo^k z0j(t~rB`m+@Ku`VYdQ&%3M$bxx&8%5``_@xQjNx|8Z|$3O#BQ_=3q^&8Fw*}h#Xef zJZ3$`M+nvBHYyg-qGw;|UaEEBSxCjd>aHh#c{)_j5oIEC?c=VPA32i^IJ?1k#oz5Q z1pgXy*qR`Rrdt|bQ_W4Iv~nRLtvavd*)V(`2(`G(hu31g7U>~Fn0 zbzTR^54{!=RGDdfj5~^)-H&=!KN4eWW3f;`hhijJDO~rW6>y&fl4O8@=YWm%_tkBo z{sJ-auT#43iMNBD5l*Cvv6|+96-V=b6(OeV2F{v#ZUTQS%RB>clLLxgkP1$lm;5-M zhU)VeVHZN0((_kw;;T%gJTMBtow^FX>b7`+eJ#_RO3CMciDN?Pn89r0V-h?L4na=j zHJCVFxvsKFcSYH_KS##lyL2S(p{J`<-&*}$o=Aej41aRRaZWrZ(Qwt z)N3R|>);DizKr6eV83E^_iNboc4yJpeOOY}DjN@LDm+l;ovXY0ZneoJR_Mw!|9uEoXFtpU z3dLtzd@UNd4x}Sd`tgL_z}xUkv6_Vb)nYj{_QJ=gu#$-g@sfuJBTAS$JP-v>P^jzm zZrM}tZ?B|kzC6NB)w#^0-6GozP)3A5;yeNILWuGIb<`DA=OVB6dEIyyBlMNLdslh` zWq^HYODZJ!e&q2%Gzzm_nxsfC_MBpzh$TBC{hhjdf%t_hf>3R`gQr&m&lD|;@|d#q zKL`l^`?6BRw3@i_nvVY8+#}^U>CxgH=dL5Mufhx=K_2+eoeyi-#fRs<)(P%jJB$8W zAgp)Zj9_22)UK9v-9=6b7lI~3#xHE{F{k!(~-rD(U7wae~SDq?&q~uvP zC6iDeaBw*#ZA!`4)Kcj>Bsapp@e0(7CeTG*PUdipqoq3xS%q|ndMhE!=|gLUMcXK*z1&_V#@d4z@w`Y>X8SJmC?>f z=gC>^4=c*KUWY=f8RumAyaLULSa7y{C$${k!^wEAcRakUim1mD0)E1&EtBh01H;%S zuh2J-)aYhQnX*cf9FzDVA%iH}h!-FBg4a6u({y@|Ey^HrJrZ={Jg(O@AE3Q9f&{!a z@B3(payFg{Bv}7`s;{r*DdlIFrxqC&HdWc>Z0Bx-FEd4=huV40a-@>sZ)}P!(+_N- z$phuewc!_+THmn{8NE#zui=h0)rrrbl%?j@J~cy=50HkMrfc=lWJqhUWyJ68BhB?f z3OQ_S%bvQgf^Y1gDF5&4<_%44Yx@5Ie6|s#dolBFnJ@Fa+VAI=@oNl5hs`{JD=ZRd_P!z{jjBh!Mlgugp#gGkcy9p^eB)I|A-z2|r4o6=` zJxB*Q*bMcF22vJY9Ym>i9Q5uy=d@IVKeb|`-0 z%5^t^AvYI70Aly2?%|*|xqLiYcj$TWL%19#@pn&tZkHdte9kkWCZ&|*b%4UG;*dF~ zLCAv_MN~tNiY6{N&%c$vKD~IOb;Ivny?9m5q276|3+wnk>)7Vl%#HU*-It2_{A;^5 z>lyVirhvvk`d)k}V=lkiz_f_bBfTZxT;0>XPgMF zc^ZIzEf54U#Mt!Y8%G#fvHe9$#@?oo_zB(+Y*BpTU_oJivIbg|sn%fgoUN^1{Elr@ z8|*lpx41%f*rlJdb0yiDZ@BU&|I_$cW0q?kM^Kmtn38Y1(<^Xa6)xV-9H zYGqfoulv3xorr$s(H8|*wV)VEnofC|ZD1R#SB&7^v{kW6(r* z(>v5F``f92kW>h9w^>~c0R3~Js2@bF9fa~XlM=&{0!1RzI7!1;xQ7-}Jezr?ssn)C zD|lsR+cqs)8|nU-c7{Ywk_yk>tg$P=Q`Nq{sSm z*nca@^zrZ#LH7gXoJrT<6f)9@d_ z^trh4=wA-Re3=7?u3Ox>dL69oj*ssEoAxthq-o9|${2GWNuvHL{3BLGr`Iv+H?mo7 zI0Tkm*fz;ap+J&aFhoPKXBa%h(v)_aQ?&a2ZR$u9)f|XJnRdG_Uoh+H5Ah!bz4lg) zb}^`6DQ3?IJ5^zeNORPwl-UvcBGZTW;IPF-DYJfTdei1YkDn{M6oC`<=S4MV?bQtV z_}}xjl>)-f+k*Te;;+)QL4Jmj0L2ySeFP_2ti7#4Ro`4ma;NT}z}{4sf~bT2b|9=2 z&P9qSdq9D3Z{^>R2GcJ{U2mspX$YE92>)r7)_qZuva<`>q-%am!!{zQ>Ur~phQ~;w zl$cL+%mk>mCyLl(*3VUra2?nKkn=~NAfK3$zAJrbAjzDgBEMej!0XqSHK`CB(0p7d zDL}$)PRp>PdQY(~P_`O!iz>R`+2z=Sjq(F3A=h0OE|Dj-ljtfOB2VGBr>GN=U-9EWr3#mJ;jqVRI93jKFJf}QN9d3Pt0YR2#PU%vrTjs} z_#a?ghDKm?0ImG_wG>67D@KE1yVjh!Kr(#>8+4?h&GGlOy1y4X|4(=Vqne%2f*$pq zambuIKLcLMNKEHHJ8jHwL;XEi!)uyT9%dmjF3K7WKv-#UafM35o0dR@2be{O;kCCy zVx>k;tnOyfRqE?kg98>Jl9^*YIlh_>P}Ga*?&0^B<+9C#?l0WT(jo@YD>Oy1DB56U zZENDQYH9zX+ysd~2XHPS0;y1?xPh=d77L$8BGKo<$8EyH*bU8gqBq2}EvKe{(&HVB z@1|-^u+?-MLpwLTn^)CvbSs1NQHWbplC z7~WnwGey&d3dO#K?h*d2#=(lqr?#K|@-tQCU0|mh9e+FU8@!hst5~{L6nb#&IhCod zlreH|mW=7UZ1mPY+OsUFu>BDc1Miai>FBLA{1he$f4Bs$Dp;GLU{6pS=c>oz?yS+H z{_PW5v8BcONQLc9I6c|k=zCMLCrS7T?5<|4x}SwVp0Gu}tq>9%u)9T*iSfn*vLBa| zoveN_rVZB1IAvdVaNkDi6ZE!$aJc^iltFpyX6H?y&g}|U&D)zFK2v^B!Wpy9eW1aM zYYP=!c;B4EEc@|`_7MD z_c+y4xr7*1w|qd%g9DIPEvns7jn`I%JN_zNSVlWRS1zzaeGCz z@KYxiHRnf0N+H>}TBGof&hUzmIwwxFC81t!QLdK?+e=(v3%HdII|vQi-JWkIWNoC z+Qr8LV_ib==kwAZKv`oVqP0Y{Rp#K!z6W(f@__jxDRt#ED4ff`^FTt{I#vcx`~lrm z`dLP4M(blCQXDN-nal_6&Nge$&=?}YXS0P^axx}!1vdrG(7>%(a}H&+f=-#cS7IaF znoCGo&v|TcFJ)QhWRHWAiAXwI7T}fdu@ngHyBC6ep>;T;WlDwSQM|!dIjTSLA{uCd zX_^HDjtDJ$Ur==88oFQe+cYpMC)@IaaL}C7GHfZU(XKjjNHMwU>^3T5Zo=~Qr&~Ak z!~@yWso4W#>$c+4VK0^NM@;FLMRK81rJFC?A={mGxO1_UWaZEEp25fm5bui$)!wlOG=rful{JP@uP3Pw!7M4YewUEL=;q=g{fs?yt;=R zG&G?VJpKZL>V&~e%M>*zj_ z53k(49H3;rZj!PTbrMiGFF;bOj*va0=&rmT%ofP*F(Le0MLR>KvFi%y@7L&x6V|t) zRyXBVaD3!LMuXkRPs+m&`#o{*&eudBasK1FjpFVxijQZ+Xbj<0pcYHRPJqw3Z^EI~ zANP6i7(ufoX!+guyUX8o0h|m|2)heG%Hpa2a}XlD%oJnT3PRf*sGRT@pjcS|y;zuO z5jA08Px%%Ha^xZDo&;*840bO*)2{D*fe-tJ&r1ST36b2C=Pw=-B4g-spJdZF4qAEU zF}!iHsgb%=Tg%fz7)JfUjBk}GZ52hYP+K7P2-TdXb3I4ionvC1uH^+L`kZ~9#&N)b z)JU?P#sNmS^T{xrb?>hv5R!y;=F)W0<;-~hHab)K5!ImjA3y{g)4cZSHD~=(gh%C+ z;hO~H(q?&YRBFR`x2+99_bI{m3K}(S2exx$ z=L_x4Xi9&NgvjON|E@Sd;mvx?BRou!O+>#l*J-Q=U#xz+)~p(^%U-Qgxj9c}%WT&& zoZAr8?!*qWCA=N8kGL_x8Bto<7QM>9%o5(XZ`C|TLio9lt#*5-STg%B$TE*?vIk9B!^S5AezepzNJBklc8WaY&J803DhDr*M;w_3-2p7U{y>9=KDsUtf8lJ6h zhf=I2=-Pj`pKih-Ox2mUJf)($E~3KClVQ&FlY$yBgYlN%5^s55^+xC^Rb)*eVOi8* zZkP;E;h+1H_nO^uXRA2xUTZt`%*1ZxeOM1mW1%GEzNB=0x)vSK#4{qU5i|A+W+z3t zM|AAHI!ET^gTu5GhYLvt9m>r)JSCtzBnd?q{$N=`jqGE7Dfyz^O{14W@~;ep+*)`f ziWgBi4aM2v#2eLTMn0L@Fl9qV(&6>lb>g&_!M3Y2M}OvvzpKyx4SpYyD|?y?vL&cn zSGnP|BKr?O)US?r5e#oM?4No6rc=c!Ca`68K%=oo@PyiR#MLCjsXq?KEqj zNRJ2!`J>ga4-;`3KJX!9cA$!wY|~V?Eal)rX~ax}dM+_fK{u8gf8M;7S0OC<*$Dh= zSVrs9=h(I+a<0nY0{ZilA-0+go1wr z@W8>Z66D-JNuE%*-kbiDVQ5#VH~ivGy{9f;^6= z*l-C=ZYXk(MiaDv_8t#)E~^rO<%Q7 zOV26M>m9CX>%f3}S~hXb=X5Cl0tiQqVI!sK3K$-9MUry-PFeQz9}${({q^#&kun8I zc|S+qna#$S5jYmUj=5Rzv2ye}Gda1JUnJ%=1ce$buOjgbf(Sp$ZD)1tnto$Gf6hb6 zl zvyCad4Up2lMRp-5X>xh;RmA6ffv#xDG+KgI5)(kY!_%Lh8?wcjAcY>5&tWoaHj&fS3b)7e~k8iZPW8$Ju`~>KgWcw z`wGsEK#Xtr%~*c9>^!dU!URnRcUxf~^7XOeG zYX&#?J=OUUsAPNX+uC29e>QS3+@dp{TjQiQwkfb5amBodeY~@1Qar$T8!q-;_+{j& zYtEvH9_=Y=Trw$wbh6s&HS5`kwnMnd(bfkGx5ITc4y74MlZZ&-Qg-bhA~G5L3Bqe1 zGXLDY8rwM^=I67_cZMl3WA(f5GD06#`P?%RrBh};P!gP+U|hY>&a|}*HW`Z~R%eX~ zO9Qtx(XMsUbtBByJjuJ9SkuDPh3%5FUOwe3Ni?ljW-hF-wjhTGLc~h-1b|tL{OI$b zO=fE*i`~&sT|Ui}mrY%AP!h4dGCe@_9!{qi zXWm~724_@z=&Lzc2phb;0@@eyW$>%!pLU5`rpQ_#I&Ui}0BOZg7qi!1#nbGWnEdn0*_glf)kfhwj6vU462Cinss zVM|>&k)sdIsyy*3oGC%*NA!R~E<}ya>LsIVA|pjn83_fiL~cl|OlL|?z3{QFk9yUe zH`8eff(vS&-+&`UNorrN9V}~U&LBIZuH%%S_@Pk{A4o+u91EVYo?;;vD6Dx7Jgi45 zT**c0SA4uho`J(@^=JI=^+|f$I+=%7J(kOly3-B?1vrMx0+4jD)4;6I#G?`Gth$U?JF%EWgh z_{rl~_*&^CF2zcv&cj~_cbTc?WH3VUc=+rY{$Y!`yjib3$!H(LjxXUN+mz(9hhT)Y zEBXC)3Q|NA8iXt^ue;z-UE*kVZrhh|x1m$-9j*Wz?xG2qOPoT>HPcqd0uBE3|Z;AGXH>yfK?(0S!`5o4T2h_eRlgk~7kW%$-COo8dE0GIZ>@L-LQLn~Cg(*v@;DZdb-vAs= z2%&$pl*wG*UFb}6g4_&)Kv33)h4q>NP6OF^lQCy|8~yYto}XcXPVj!66N}BPy!wOe z@el`6bbW0QbLx%u*a6tX6kfRS=ZDWqy_(|7h+U$T(JGkPvA0*~8yxLY%$sPLz|HA5 z7rO})Q+vR~JG1*yh0xF`%a_Hv@fFAsAu*;4=M4X4SKrk9=r&@lx^DJh>9?LsuLf2FU;g;@S8(B zXCM>CQRWZ(6}<87{#BDFFw3`r;`JUC`Q?}K$ryj71D%H7n4w*yhQjl%nZpvvfUx~- zHZKOvbA@h`qGOH<8O|%ZnuZmou6(` z9gRUty6z*$#nIL`Q8M3bBBN{i)oUejigNWVUvfyR_x)_~KHJ5(?>dClFpa;x{LvtQ zP6@0e7N@7Y&*ur&XYyox)N@{FMcc&|R-zbL zKrso1?0cgIyH8)$*MIxr7Z_;z<#}#sK$TdZT(;pS(vJzvuKj}D7c)O==~l~x3?^-) zodO3Oa58zy3{4i5T0<P-`I{|XOKezfnT|=QRgJO=lSo7L9_Wn-@ zAa_(DDQAOSPfDWnj9}Yp;-gj0GjOW(k!kj-PaTg{?seokR+06T*y4$1uEKQ1HxE;; z1Qa-nE|bQmKWeHdA+SDDo_;=%HVLTZLsMIC@)$TB4gdp}KbNbh+#VHUS)K|jQ`U3! zzggvZOi>%|!<|Jn@y3B*x!oo^Mmj@8mZ5J2)l-TJ5sFb#Gq~_o@ttWWTPh zr%%R#f`(5Vp@iDxB0T-A@mBgyWuucwY+KFWIu9|AKmb+L4T#s4h*#@yU8$w(QGy@6%QLy3U zT6*2eF4{uTGFv`1wnU~DTD<{)^K_9c$2swpy1x)Tu`Pq-fWFwx%)n%BFB>?zCpMX zkahdOyMfc03R)^&rJIR%7HP<}Sp^a5XKKTjbcE5*!)TL_kz!~uJY1vqtn9|E*t(pw zXKWH5?}wj;CXGEb1})W?ojzMfB^>NAdA>$2(A7K^-!6I?p7KJq7&*1evajzPBo-P@ zS0D;I5mGs6Tyap7W&I?0@U?ie&`M8Q(AZXIHvXby$>YIhc48A@L79wT0oqAG7XBgI zao6{pRqV8k!Fzp%N;lT)mjmUPdq|Rr4r>F$-{k6LQ}0fnng~K+*>(Cf~1k5W;=<} z+0R@xaj5#K*jlMt!sy`D?azHN{fD?so(Cpq>1bA-KjP}d9W_`vC$a&q z9pyrV;!>CmcKBZp*uF69zMx7+Pm$mP;pH~~c6b+g%;jS`l{Qlds8J;XoYRm}B4e5) zHGC|kTbb3+b=F0M7OVeTsUhK%rC&}zt>O`fVSBvorH%ZP*S-VkuttM-$t!EmX45pK)Q8jrA-qcuhO-6i`u`D=}rx2e;Y=&sr$p0A7#kE^DDsJ`}5$b+xe zy2tmXv;5&D;7LVlcYFp!FB$rFrm$?tS3-Xnj1RA7m)Zt9Viq@LAg8?Fb7S)<8&@Ar zjYgCkB`+yn#YI#0cE;{eF5wz|BqH1~0v%taFOaMpTP25wKx1F(q9 z#uSJz_(u6-7uLyt0P|UwpB`}S+5Y_FuMM{ioMdW^q>p=2DOC7z*BN}uKLqg7!LfcC zi;{qI`G0HPxDVFDJf3De$$d!{$TE3@ily``&SN1K%!|uw-1~-7r~1O2TaWM!MV;GY zZ6_oUjQ=D8x$bx^O^u1eJp|KJERALK<%;5EcD$p?<+KaaATe|ZRW8ne?nhG6A*yaI z+p>+{iDC`s*qsnFqP=*_qx$ldSGex5H{;b$oz96g;idEXjHyfXzd@7x1DQ`1#$k=- zC8o5^VCy5d`emG);bj*6Xhb_xoswcq{H|h5t|!DzcQtU_+#Ld^WjSQ3GtbanA$uaM$9R(KuT)<|1*+kX@ueHmcEZO>}Jc+L5<|{@D*Dk$ne}6VR9QY!AwpEqW-$ z^A%XS@H>Oz^hTvqvgf9B;(fcDmZ}46FHWp1UQz7mEU(9sFNrH>K39)iI}Gsk`Ey&? z4-JwQssB^&NQnp~Drr_>-su0pQdbHLBri9Bve0&aKkLp>wg{YX>j+PmCwj4TP_Z^ee;{G*QbhUZ16xt04?w?T@NIi z#bq)sICq;=@{H><0H-~L$i$air;8|3l}+A4deIu(uNl2{^txDRzADDhH<*>&>-y4l zsBw_8YRyyXfVIH{Wp-oumzw{AM&Syb= z%a}v9WT5oF>yPFNqs|k0)#mf2j3JYf-@woek67*Ae>4mqGz2W;?HzOED!?Q)0uM0G z9UIdw`;pG?waEjzg*)1m{B)bUNX3HR)nkEje zVi2x_JvgYVH$eMhNTHIA$rHpCAS~8DpKy;0@tM+WD4T*&hV30&@A}1RRrw4=V9W)VL56Q-4TV>} zQ=s=hjGg6Q6YkrF2crd~8ze>x(jeV1nh_!((ozFPC|#pQcSwy6K|*36&FF5VB&4NL zLiGFWKlnYbx0n0eyYBNouH&4rA5*F39keB`us&H=4d?LxRa|!4UqF@*c~akj!k({W z7xiBa^7+JaMl9#dl6Ew~I$W&{_Ry%Ook=0_9MhU~7Esf-;aNg9284XGZq&tn{2S9@u6oR)2Co zE#Sj!B#jifE74$%`%f=$K`lM-pEP)C@nFW-)<&k-xZ1hWea|B;NWYdT?leg+JmgBl z*RYVyFP~>*McLad3_t7gI~AP-jAtxsVb$A3^)JD=D2ywfmLvgpd zp#kh~d;6BZmJH()xPhaBtVyH@3{Ia`ZxLd1B=b%9cjfVSF+GN)?97$b^LM1kXEh_3 zCMTJLYpCy_`&Q8B)%_nLh~eb*w@zS*PVbtl3$TZ85##J>mdF8!9h7)WL%|(=X&$U| zw>NA^Y&p=W;tVNf^!K}6d*gKHua{RD3;W#6+tB<&dUz%gpWG$!^39t&v)MTvf&4K@ zT-bFY3SRan{aojkxI^J-%uxH1)J$V8&UAKdC{^P?JoDy(9LMY=s`lWj(r}0L0Qw=% z)kWG%mmz2tW>>AhU5WtQGxy3p-d1e7o-+R;l~y6P#Ck-`c~DB9c=?JBt-3;%{O=wr zX57Vg76Rr(lE+BC)>nyI>%JPF>$v7F-Qb6*iGtk4^E61_1q?urKd&%FmF=*IVD{Ic zEivoCeBGNY5+3QmIX+XyeX7iw_sIlI64iF}K6~E?=M+d@;1V~5U2C=4ubkMbRlJaU z=&QQ)3Y0698PMS;JusyP)B7;0UP+{=J5%|2eS8sX1x!UX{->`!*fQ6jKp0T8) zNtZpxvMxPDU)1!sUH)c%l;`cVrOo9-utxX|eev}7=r1w( zy8SOr>jG?LlgHCYE)73mm~}AgrW@?&?}kQXeaAEMpZmiI_e8oWv5u6qX$%yRHO}YQ z#J+24{%xtW$hSSoZOn&fQ$<9i<&^pVp_!KcXWj(2{15Q@ABQO=P7-3^+3+B}rQ51s zqN4c@>Gl(Fqc~sllw@hznQ6YMu}f)>AJ7V*FL%P{nHJDHNAsq zq>I_cy2(UL=qB^xE75kIyrGw~sONNkG_DR~dxfJPJ$r-H?a7}C7({Mo-g~o5d)X;D zY)t;+W8ptz3jX@4trjOJ5<)%4fRksS~i8@^}c(B9Em`0`SIMTLgFZ zs+uBGF{i?0!Ub}el#E7YrNtimIWdcYvPLd9W`Mp(6si0o|In1`>LT{|Ccex}XS$D{rM-cT-^kl4!FbLb*KM|OHUQfg{EObmWhdZWY1?pE#Y%VzO zul0y_fm#kr!JhKdC4hNM7I04f6~Y+K>t4mnp1pEoQ6VxIBv#_ZaU^Hn*}t56Jp4g% z_Utp=?>AP)RTQKTA&@-h#%&E9k;T{lI9;D0`oGN8)j?u0!3DDiY!5xx9U~#KyYRUu zVL;&R4!v>Nm_0_du?r>_@~yf@J~m}ZD@A96Mrq}x-J#y~4Dno#+#yVd`MhRFZrYsr zk!h?cAJT;!joO$`F{7U48@Y2kg;?Qt3|qt7^n6-iY$!BTV5)1~F^TE^m(^x8!PABj z%qMydA=b9*Iy%40uE;fV;`GEg4m>AYS){}8prNx+aViXs6gZ-NXS)hh*i^(as&uu+ z9cG~-4Ztv?U4jN#Z?)dw>`SwFSB2BeIagN3#Ml35-Np0?Ns!5AaxTwt2(yQ7v#X&9 zdxD6TV`foPFW0&ZVf8OqRBF)WdI%6XQaa2-_Q#Wx*Fh8Q0u{O62Fp~ANs)dZuu0d< zNUEkG^B1?eLixPP1?I+)BcQ1vEmcb=Vn#~ywZluV_Zs4t=0!hSE5GOzoiT-j8$jNd zTWc{t<9pH;G1LfJiZtD|%D~72Yc)J15OKDg%_!3y^X&Qfv2*evjj+^3;U^J5{wh6# zX1fqL=j_ZmA9ZVXQ?0HY`O9~+uKatq!Dkl_mkx7h0x1-!){2be zFOliN`x4D2nd31bE-*TLn83?eZD%dh!im%=P<*b;$F=2o6q0i}ZfS}0M>*Frs=HWv zg+;l&Tar87*ulEWRv4d`IsZ!~U7qv0OFMIrT%sL*Jdsg3*zo769YdwI28q*H<`H(jhSlqpu*cu$H#(s6l zp_I5eU!wR_kYIKV*fzEj<{~oGWZvjU6=jp7Y+5LKk z#9=9tZ5VDULGh=M41OSsmw<>EyX;}yuomazH)D(`f$GJkIC-<>im6L!6E!aHU>K5J z!ESh^N=_>UVsJGQAB*=?Y93m}WWD0-396p^(9q*Up)XLyEvFYhQLc*JSS#rte48eF?8)$?2hbk0yYs!A`y~(DBcj%mMbCxp0nOrUlov4u&ZOFcIu zGHFwd+k=?^!I857Y@sfMU~9JrbhAFt!@2GH;hYJ5yyg%HNs@>CJw1yLJQ zbwcJpK=ZwpT>+k^TZmqjgEU28ct?ifRoqi!cJf6E34=HHgfy27GXV_%Z6c^D5L0-w zV5uM5npIVs7-J0i!i8pht9{kg?ySfYoxYILB;e_PP6qn0NrK1OTt-#LZzzmT`m6hA z!i6u4yBfEJb5uwI5}wXfmVVUitdwlH zKwwUV^iQw%O}M{AUTpuf!g8NQ>v*o6h+|#-HGU2vE3QbDF0e~YFUPMFYsI(WnO6)v zhk3WNuFmkt5gw=KrsNu;mKPo_Kn8Xhm95{@Z3XdB#K35!4~XH zsbExm#_l8%oI>aTHg!;%&<_LTO*0Uit~lX6@uF^*Ir0*dmqen)7ei=Gsi=h<2a?j= z87PO~`1Hhpv`7r^|7TR5vZ6)fQ;dLmrPivDLbVm^#rQ4=(VfdS#$j z>+EnxIKD7N{$&0L`<6#_q4M&kQ=T8o1~;29RF+$t%y)q?j%&0UeWoeAz5DEV-VZ~O zd8}0BUG25BYzhSP$QdCFSby(toi`^!fp$vgZ-lso*7H)aRfo28NR{E!xyJ8VlW)6Q zW9Jc~b%#_>e@J9}ie7c$`mjJp#o`;AKbGPj(t6Hn#sFt;!P%E9!RxGN1WUWtVM9A| z3d);cMl(lMK|#s3~ib(gadOrX8^S!UWE;-f?{)zBL#TPrl$V^;L)aH@Z+Gq zBq|o<{^|3{GEZ3!*mrUXaq68OYAhG}tOBfSY3GI>zVKyr&gF$nPI@q_Qp*i&2!z*hMjU40Jrr)(f7J3G{m}6Dg?!a6>%*Y#AC|k^6 zu){WR&s7|z_Rq_D%#GV>DRNcN&oIfYLc!SXZum(x{G_Q+CE5;7A{t=AxUezT3GRsket(5#D56xz&+M*f6L6&^hYX8y7g5q zeltXWrU1%5YY4mQ+?tK1^XcBz;@3HT@tp$eyL0o$wc|-w2S#;D=5Nr>c-l;0Ytcvi zWWuhJPlb)sZP9u+A(8?S%2E+8x+651n)4R?y?+PFOkFG@+tzr{()5IdY6)1`oi<(Rh~A7xK|@iAOV$5*BoD z)(uXMH&-d|0{@v$s@dFnjsaho85h{EY5-J|rAG|Q+v1tCj70`}i*#Q!TevX3biJW`Id7`2qfh23}k3yro_?V_NAyxQolg=&R#Pk+t%d@DG* zOi+)XqL}+jcFPZe47Cy3eG;7i07_d8v8qxn)q$#r{{Vi#;P;|Tt`Lec&!hgPfR@%4 zYD?Wt)ZNFqLQdW7WK*HBsG{>6=2b2!ORthHqENgoC!w$yE>SGnhwl*88Su^9NuLll zwgt(>uj~-N*jr)eB&xu_S;r|y6D%*YV^0*F9UUaXn@?#rhYM#h#qaKass3dgE_*(W zF+vzRJAxT0kH|+>+n19o@*Y!+igl!0iq(IFG!ouWxx>sGw*KKc^upXbk>c!*Q0RXE zm60R!`L*Gn-OX!H=1zUQdkHd~@3jLcGiat4X(VV0% z>PEXcjH>4?x-xsw^!Yab7!KR8t@L-O2(bYA6=f_m@q=Q8C&VERmm{W}5krJw30Wf6 zSI_b~3-s1qb-cX6tGt*i$IjRrWdj3i9bmu0oV#puZMSc|`Tg=A7b7PaUhjyI1oUNMXpNR7R7eu_Jy+t_=3*W6m*@DVUA>7cu0)G?Y*56v$aw$oU*g&0 z(=2(VMsd(lJ>K0MI>uYdUf7<=t#=tbsDertLP8i^<2dMZ_oxDMLVP_P@?&g>3 zlmyBxp&B6Ocx_Ntr{*~OOS<6KubNE^j$L@{`Il-H+qCxkTK9~-XX+NO>xtK-b@*K< z)wD);#I7TahbX&%TrXuv&{11FT<~MTT|xJk$4$b9D=O9qZd9Uf_yZ|kdBFX}$+=8% z2PJ)MzchrNxhrYjjuM7mF-b0(hnZiX9!<$2GTic)MBRz1E6TiQi>GFrjhh|F#Zvw zOKO|#`VI3!#p|)Bk@sQTVJs%h;_Pj6^}NGyzZiDXO;1*`kWPQ+E4fPkp44bI0bXSq zuP2m@mx&zCyBf*Vc?6x(7u$k-*s4nN(OaRf4yF4hqFd2Kyi&@W(W z+8$PTmTGmEjm%f}X2W$-njnx{9)k6P6)qQ7(1tWeWG+*9PQ6fipI_iwow8)Ox8GIM@T>g?c zp&s-*((JN_ttYyq;XY)Zd)4-e8OG~bqNNI+Um{>S?)J|TddX31#u0Xni5``H)h=yM zYlInNwbMM1ahsu19N*WP?i|ciC{B|3{rMi^JJqc65UJH6$|EZ4yK?U$Q}M+_<#UF6Uzww}jk2jP-e;Q>q`K4s4B z6vzgubk=q9L#1_wxvu}2L;?O={@+1Vez(vaB3N|p+!pbOU7L7vPx%cDzgLbFQ0}eP z65?u@`-};c*w)QG;eIKqdg+qutLj5=1w??el$tLT7uSsEDo?4^hRF%SEHiueuHjVv zI+iqos?hdtuldex3Xf(jh9f{LHDyB}WwBTQMVe*rx*b)$Ovqf0*SXd<%~igZ1z{#9 z#PN1ZpH(uBpeItET1Bd-5VBpy*H3ar5CIhtt4VFo7n!3WK?VbuS09XhM1~2Ko?QI- zphNC%Vp!kJts0@6!2C1=(~}StY5J`uSv^WJk(Y-konD`}tBu=L*F~gR=)}yfV1jMJ z&0QlS1oA$f;dtM3M`)62JAy`~R8m-B4SUrCO<$V~E8=Pp!Yz+Tf7vD0lf&*uskouL z4O6rpqs^tk)2~{|bFDir#`e5J^>@stg(>^}trh#;AC3oqIz+p-kjaG}J%_{USPi+aR5|vP@J$(rse?tM;OnUt@3>Jyr^Vn-v@YJm>G=9G zYtC3E)k_3tlMD#l+K+>F6PT*{g0Z?mw=Aq=$bQ2b40=+(>+alcYd%<-O*kI&mv{Kr znlE3Edlp+e5Ynuy1DWdO9Y1fnTUlh@bIkk(;%W11Cvo=5y~o^wBx_Mnc!4^(mIFy0 zRFK`CejD08d7Nkd@0mlH^+rF((tIP_4rg77$rlh z-yXRJocA-jqh)J(p}F_ik{#0!B6p4Nda6$PMx7t;z<2oqoO zkgfF0!D(3pFmY&x`6GVD@`(;dx$0MEEOB;FZu{(*)+W8zp;+}od$faCgzHLdo2F?= zC4UJICnzY(tB{0cd};>&OrqJ+gR3y%GLBn1g=8O1Sn>Yoc&jm%d}BtqLt5d-{6Zr+ zy>RbFy-FY^TBt|LfnTYO5o*Kj&M>>rdg9i6KE-)uZWspWx^p4Dlo=#T!($}c8Z2I{ zZqdZP|B7h9&o0NqnxJ8}qsZUmlhi%<$4G`R%pS3LG3ROK#*f;!Fu@4!=7>{@J&Doj z5;6=6!B(Uzr_>Qg2Ib|8Vh!_YRB2${JN@rPz8Xa=x|=^AyphQoPcNCCuxVN$f9hpL z*d6N=h(EV-XDR%bF-;gTv_=jeNNQB4W`H#*;mWH-9m}rlHqRHZT$_=$6GvZS{`!S$ zf&XquI3kIb3eOU4KkpABf2~;638H!Qos#TgSJ#i_{SVY{qB%(a_+_A0^9xrUANQAp z+a=Fv8kge*Oy~M`@&~umFe*hb4q^=rlWkjS{WEtazO2jnFK_S{2Ngvt+J5bIm|7;c zGyG;SsQb0|_~9#tH~m6|Nu()Xff@S2gS{NDg}L4tsh?eblpXL%H5Ar_(8GD|VCTUUMJ9LO-4Oe@dQ82zN!Fjjx;YviL+ zZ5p-v-QaH&9<*;5Nh2*lirIJgzMZx;{KvB zPX6;}L&n6z33IFGzMqKqGBUYE0{is$!gn>Y)8SU+QBSRzEc_o3<`mD^fCqdZts#5Q(5A!}~t5Uw5ySHrdBsHFD%$AVs!41*rt0 zq_c4m5|l{tp5!R}`qq5{o|YKSOvO_`U|)RF0}wB}As)9C3oI#(fp{v8nDC!`R8ojj z=O@L^)pnl3da2`D8>X0~m~_1A%sfYg293aoKmeqSyi22@XjwWHIjXA3_-CrEYzcw% z`Xmmm-Ypk94ar6} z-0*wIpTRO)V#nDf8yGycn@vmV%tE>}Aux~V1>#HApZ2Q2eyH(_D3vG5Yv>(gV`^4b zcR_-@6s|}0=(UH|eC98+Z*VT(AeW3U5?QNAP$v&YozouCu zZ?aLl1XuL%IOld5;xM{IcVZ!k;M)HuL8(`8ebNd*t3Uw0+l0HN7Ufu2rq=5h@s0{mC z9j`bDz z{ki$my5e?OfuobGRtJ(Q!?B2MNSw7Gh%5G5gpsv1l}}nfOvKhvbwy{^Dzcop8DRXb zNiV%Fv89IyzQ9Kap%A@TeONIMb*f2#9H#{g^`1z%v#*Wf7exUq4fuE>I|x#wjy34= zZf9(36>-uO-}`xN;#IiWN{F#ME^N3kJEB2;^o&rn+M(Qi!oVfdqm}U4L4yBGK&^(! z3QP-udT~+|7anMUcQwCpil=o$2tk z+TfpXgF=ZKN(kcT2T;>ukf8Y77zODo8gN&K+m0n|I{G_bXV zj*?MN2Twn3^F2&{f&@x(I9RQ7zdnE-h82GHHai093EAFW;75_iSY%^>Lcte9c3BPn zi&!6cu&lwtP^rSH+nEt+K;>4raC7qfU-g;yIEyUVs(S`RI_5Z-YnI>(Cs7wxJn)9> zhn*nOihek#y(GkC z&84Nr?xIQhLPk}k8Q-_-BwDwXq`L5lQYwfthE7Y7wMLcYM;dIP_(-_bDrs^oX3tDh^M|elaWji z@SQi=3~22N>CjWXRlE62^20$8!J)})jE6-=Hd ztwOYAN_ODJ2fgo9qy;83kJKLRPk;N_mA+E(otc4bw_5MQcRkf+U2GjzCr7W}C)(dU zP|R=f<3B)^8cHu>eIIM})4^rPH@AM92E*JolMJkTTiK+t6UtZmU&IYI#3Oq<1Jl0UV8I@Q29KDVVMYX2nvHo)$WLslWU=}b9&9ai3+@X8QSZA^=0bak1m5>Ll zc(qn7nK)nW;nujMB$SnQ(^q0wxXh|qRJoxJm)Ay*r*QJBklkzY{#0?}EN#HYj~`b1 z*SZ_ZZ6o>JufW+U;)vLheaxY@?(>C5U06HU>g5@ABAkjuC?9cdQ zS@k7&aF@dPq^{UWF2%PE0P0&`xhiSUvP6@9B9Fszp7(^7|FOEMB6E;(7!&qDnHCJ5 z|2u?}yPD9mO>j6LuN%dAqUmA}C^XO7_{0U18@itND*!203pB$->Da|&e-yG_(2513 z?hg{aK2A|2AtuPL#!Nj!kQ zDx8N0t0P0KxH7hL3tR9}g`l5ir37J!{mYt+)*E8~ZG_>P4M~ zl|uigSK2<@CfQWXk;nBiz4#r(p64~UUKhIV{)Qp!hZF3UbkQ^|$PnwGU+oe4B(4(j zZ$7H>PH@Cct(s!{=3d5IpuT5Xo5?ewx2L!-$jS!mBxgpKK)}!c@{&EiSndA@pe%bq zRoQUoRV4}W5FU@TyzDv=pI((MDf0JA&#NLFE!JyW$e1S4Agbp%S@%_%84nJ}zSlhK z8V){u<`Y86Jl9ng=C!8JNRE?qeG(wEJ?L!~z_FE-#;=VkNrBh{8Sh;Cf6U2shKzse z_;6WBNuA2wlp%?c3s0ae6fpyC%W~0^`n2>YeRuGsf$^c4=qErLwiP;Yrc1rC&FCSZ@<^ zL3~?fC-RciKEMCuJEuLoz)tg$;p;+xZppxBIiG*GCzhgTdXq_XV2#x}%MF zc3(UHHP03?P0`y*i=z{A?DM})1ONOKd}%yC8l1i5b;57=gkJGLzQJb~<6 z5ABE&YNQP9YLORqH?cdoyju4db?@Ivk0s2k*qtuC>@N@Qbl;)ewbVA#;njAg z1~qd^9@fLz!VTvVZxh|{rv7M(JX+TnCmwAY-QCoA@WLMY^t_w-C|@fxOZwYN-Us#X zuI4vti}dk)Qc=p9v3hHL3%8aZYhv!e`qt85u(Mp+)BV{*QH43EGTJ>MXQzX;BAwXpP91Xi8B!2Ya3)!JS{=QxV?5k!4^~ z=C{&sGP<4nxW7x3i>Q4zg@+4Akvv;CQTxv3;?Max2HLrvuMg)j*wR$TU*0yxpMep7Orn>5ikg`S<)X)Se1wM$kNkGU8&ma2_8*$N56nDl+>dDGX?HON zyuH%W8P#)#=}>`|FfPA%1Baz87H04Xb{a-z{XuFR6y`VVw+UxLF?mXPj$L!H6W=N2 zTo+IpKW`7g8UD;I)bX^6Esw6wL#uWJMlAM}-e< zlNwDzb|}i=+`0Nrr97$BTt4bNyh$i0!BEOgn?K5{$)*QC2fWQ%8d~Na!9(uW@ z>bDBA0q!|GFGvsW{0GJeg-refkfx|bf+;*SxSU9v4@P>T!S>&qrB;-~WzSjRwFcIu z@z7vpbIpNtK#G+4fp{l(fdTdIMPvhV1=AU=ZX~(HN;v@(qhX1l+xHYK=Oh})O=s=p z&}6=PGjN!{#-sE_eSp4D86dG~B6YwJG4r<&VF}LDjL1>(mD%`o$6j3=hWRELKJ_sr@V9sYp4n z)fo`luk3r>x?t4nFE6(LdQ z4A&Ax^aqC59-J*M7zt$;cLa&pl^$CU5dA)qkj!ytIH@C;>75nma)UNenR3aNtyiKa zL%m?Rx-wbe-B{4#+t_he47U91SFi58JJ%Mry@j&WLcQD&x?XYjt5N#Q_`d&x7T+1!xP;O1+2$Xs`G-9iq6v z1r^o+$uJ3=%}=vZ72ZAe`rsQpfhZ=KiPBHcQnkW2$|{2SU(j;n>(9&sIt}^lXe`tX zzwraE8WvTZSv9vcGSZmP+@f^LGl<6;;7Axjdrfq1zi25nVv-%tVh!5Y+Q8k9bRUbR z%0L}wO7m^qU(KZWoPQz#UHB!4#!g%m@aw~4qe%e#qp@T#sq#8+JFa&L0Hq$$4J9`CkWj@q zX>&^_IH7kUw8}ZeQ1*DhAv2paso2liSEJ#T_t0$5eE+A4m(Fnm4$lPtkR6druUvON z!&d)gRh==$zAhEgU_*wqQJy3Io9N+pkFfE(uD+`@PC9 z_!3if{h^XPZh%;Zoyg5Uk7OS!mi2zNprm2q;L#wX;y3w#k#w&J-wD>~Ar?d##e?7+Sp(L%iEn7vUJ;TOJ?nP8N{M^EdQpIfz#=8*3 zC+aNPd=ZAv?4hQuX zv*K2zg*{$3m4K5U>i?)Drt1he1@?`H9yFLq{$i&Sgzt9AMQ!Yb|3IHUf6vUC=--P*+|RO+p>#5 z#T%>*HL`ITfpRlOXy@#|2V#`c7zxe8 zPjE6X_z-8bT~T#5Djvocv>caDvEMHc{yV|;EpDh))Jgy_aofpqoOt5h#xYv&ZfpGA zF3V#Ev^N&`tnxs&gLDL?2XM%^b=7{#+S4=fB{QM-9xogNl^;fPfG7(UwSc$0na@WV z$ixcq1OodI>kI1OL8>V);&WOCN4y`TqO}D)vL_3vUYZJLMJm$)zuc3jA=iCtM ze1QFV71ZY6hVU6L*-qz>g8<~DUE1clXF3?Z8A zC^;~jDZKv<6ZJa!P`gg?i*$7ZFwusjlUPxPpQ;92Z|Lj3C7%{CqP)(>4L~vEec4|Ar<3@S685T7Rwr9?eh}4qq z5!UQqS$gw;{L!(%SB0ib6~j=z4x90JvyDPsobaLTf$=mWJhf580v&@VYeC>`U3d3O zof4s&1J#~fBKvA|)nJP}=vg(>@q4dM)Za3TBhuu6T@pUMw45u0RLVaK-nT1h8k*aL zujzcs71zZ464vzQSr^yjA1GZb8fuI?do}UK7Cub2F)3YCO!$}U`?w4F^oviQeo{El{dFEil_iqP3ajNZ? zaK+`$?|6|SQT(WIx)S41p$LLiEYP7(Z0SCS^ar9|H{PdJgUbV95v)gElHBH*)TvkX zeCpPewS^33aPI6nhbJMx3kw?!!7^~+CG3!+BMug+3`@dZV$rq-kkq#+VAV6QpU$4z z3iJF2aE#=|Q+L8!qXbMR-YxYWp?5jk@=1pBWl1{az$L}P1;k(L9yL4{$Tw`b6OM+y z6yvNK%w;a4?DMFONtf0?P*P_&t~N|mMNvzCRifaCcE3$oJE17I{J1gPkJRC&j@9Yjq1f?ZUVHDYd$-7fy&D!I%&R=-hM%u*f3MHSsJ?qK zxyvvfJIK;(smR@rUsxh8p2sXyNtf_MZ_C1AF|)7r4V0aD{e)}PB$yO@M-bB?gV&lw z?`)nCD%g!@XV?-(+4X9?VYsA2pmpQ^ozR|_`>ex-E{Q3&4B8ap6GzLL=SKR+$SPh8q67?tumFVp9B0A?Dl%nhG+j$bt9~$uGXHI zqQh|_q`;yyIHcyLWr2;m`Q9$|V9xni(2mlS<5H554b9q{<5v?u#%oGo{Pg{=-y5~h z`JG4>5Z@Y(zPk(Ej@(TX*0Orvk_7Un;Qoc(!f|-vsq=NANNYEBW|HQjAoJM-M{nxX zzpc5hpj^F|-`?8o#JpnVegFLi_#&tC1oA2_P_3J0DjqF5XXchv?IP??S)164YLl_5 zJA0t}$8=WVbE}lV!lowhn=m7FPjW3dx??Fw{;k4O-R~uGZ8V3Rnpo_%3gT@B-+Rqq zHCF&8FgH(X#m0~wv}&Q_Z3s5ZY=|nxNZ49K@Xy3_w)A>^+s|*9LGnlkh|(ZRV zR?&h^s?&vDLOQz_hu`@nX^#^=LhxLz1gZgK+}%$18z$-QSyK*GZ*^q>yr?CK^Ag`z zT`svgb&jOzp}Z)-5$JfJj2pD>3-;sF1tIvf0!kF#aa-N3sAf4Ta8j;D7Z?&mz0jTdVh^@i7ejT@3^ zpKv>dHE09`-^sN)-ZM;4vf{gT{VUZFUf7L%hOkd6ms%UnC`x~`|BLJNsiZ>)MzOe| ztxrbbV{nx!qq$trT;~1TU*Ju*23fy!O2e)_@z)P9Vae~^pH5txfaJ4$hnaPYzcUW@ zo|SoC)2t>ZpE3o@{bj+p(Z^en75&#%;Q4Gn+SN}(bvL`CkZ85^ad*=l0mhS|#&p9% z05+s7SK>zcf#JYBzEY(M392=-IJ(XKteX>R2x0E)!`>72V;sEGdB!lw5L(gkJdI`~ zMR(}S0Zk$?qGnVN(I*Foyzy;OTn82xurjKye|I6gxk;mlpgE4v?d7;F{4- zZ>oYS^jj)T8cHV*Bw)m_l=}6!>VIKafd6LySGq;Q@%O_KEOt;b9LLwp*zwJ0DwJWG zo1(`jgYatObmXLI&A=9hqPlP;sbP8@33tC^uqyd-SW6K=pOr%d4pyhiy)k4`t3+9a z-6fY~ED70ti}VF^f(!gXo@wCLA2Xtdn|WFr=8f#8KT}AXaKmJ$vKU-VI8`5AXI7>P zZQ96am$}%88WIV$lFE7)5_yaS!&M4!BP{e=RZdm~@yUv%=?XvutC4Ki9`Z&pMA)QG z(huL?lKiSk9G#8!d|uT@K0M#QvB>BjtLM}2@oVc{*n*lN_~^HN?)+PF27ey%O z3Lxp5BbpgSRx8qI{bv*}UpXylf6%!J^onE>(@`oa&bwd_JSk7+6xMXO(pojLNo6Ix zOqWO#!%wugKC(H#{tM~TcL0kxO7bn3si!N>Y7Ou|9zyMTey0m>thS}Lm6PSgIE9oF@W26EHYOO4^ab4x#SQW+Egm+CFb6*>I;#cGLmXjF)>^2{%uc{i z@QY>-#$l%>39*FH&m*ul`WnwBo&Q`SO@?U^T3)sqX5oQKiF@kr`uTV_pOu*(54;t6 z#ZHw;B7rZ-eD6+B^&93jO?}3JWI%%iYSld|3E($>Onjyz-r`(_lGuDFP^p1v(!MNX zzF}TM029^UeF@TGIqZ(c)Q(W9HN?XSvg?o!s)$y$GvLhBGrI zFRdua5e{_aRbt1HxXfJME@FjtM*Y96rk#epU8b0#L|TQVYLh7eNy~ET@S~yRkC&B< z1os+^IMV5LBiv3Pxc~f6^hoi9yitVzUgl(+Qsc_x{(H)b8#pnmi3~)2iN6=14j7T2{*o(c*b4%z;7Maa{*pZ3?WjHw&163_nVk}mXpTj~ zq|LbC%gmpHZ%J>unS4nbGKGU*tV?qD`oVPte!CTyGE>iO2OH_)v~XF|bq@g~b^(c# z>hEX_{t(V}y_j`5PN2fViJX3k!WoVUe*NZhocCI@?NURtX$vw(HLH*V3?7J?$M%IU z9?;!fbg1&9(5)J74^WJrFtYGUAoT2jj9<{~(nn2{Zisg|VCjvbXK3YH%3t4$2=4to zs-1fub>mgQV9QU>DIicZd^j+Q`G?h~Lz{x=9J26K?wdN7z}g zMb)-#duWF41_u~Ahi)0V8zdCzt|6qmyGz0$1_q=B1VkhTkWK*s=|*WJZq#qSKkz<( zVQt%5*SXH?IQISIxf>o)yA^gpO3V%C&KnxsJ=j}3XRMR~tu+S@zNJSPwrd3F9f4qO z8D2b!1A1V#qGhKNO*!giCb4bCU-gGZPi=Tv zGMX7&eJL`chcH5;G88L;X3NrJwhPaN%&ApU$d1-xEhH!tr4<*6tB%E`)nUiToT$c1 z5TK7l=Gu^adZr0szGY0(!6KGS^KQcRi_&{cSKE6>Fk$quR%7e&Z;JPRnUyYfHI+Mf z)%)-9LT0#Q!>2m)vlumMpoOp1{MOikW(f(CE}c4&tjp`ILt{<(CcGf9+M0RMd`Gpy z;5IZdXSL^Z2iuc9ghIT7oVS6`Lb=Yn6_r+F=e zPXv>&ZLb56Mhn=O;#eb`K@@dm^=-GhRouZJO(;v0xU5L#yFF(tJwP>!IaF)2elDIH z4yli(Mx>?h$JbWN#N-Z+ai!F5ln6XE^ARpQIrvG-NeT~(Kq34V&A4ny9cH_Wys1n^ z1GeAPPz$o`ZwR&iU$jeGmo)Vh0^9&9>TgpS@W67r!N+vBxKe!+B=nan+lJG%oO(Vc z;bgue?=LKPZbkQ6+-V5Am=I4krqrn%QMg#;2a+f#7KFVc=r8CvoYO9L))dqXnRSm~ z*C?wVYk`=AAo4NFM~ImH7m_nLIb)aB0sV1hw~W6acHT_f2vIJ{Z9qQr0b0@ONglxl zza>B~Pn=}^Mn(kc)}m>zDt~f32(M5$dG7^}M#&*PPaw=M97XcUX=g8IzblCFmT*FF z-aJ(o#d!Er=vF{RPnA7-o~lc3b15ZO_og3#lvEP^&sU>eziD1C>t=jjq!*YMw9|KC z`~wgXXievg-7L<*gm;g6lX-BhAUy=W_e6E!sy9Z@9#e`*TsHuqv9iOXbaHqb-134& zt=Jfp70eqxP6->dW>6)3IVWsbx`a%IiIS_uSLN4*t}>S*0rE?d+o}$0Kg@rYw#nTO ztYq20dV@yK_$u;9(8ku3+<}MtKVznS0VCKrM}jq5wmgVV-RIs6@P5b6S3Sq;BkpG0 zNN!>7ie6ox>Q+CIVjxxi{^H)w449=4H*pEAEhGL+p#Q{(B^k_~{u8%gb2@3*t9rE` z@xt`*m*__f=y9-`!9lDQYzLb-rP^}ctwLO85BuHNsOC1i;mGPW{GwhZ_B$C{_@?e1 ze8foXXITyYISW_lT1bixvdO_Il_HnSn_xa*(dR9Z$+1qS19Urb;aHA4lc*&3tpI40 zPa~FQGYd|&lj57p-B}axv2+6`&PNRMKS}I;_N(jk4iWy~XoJv)xELiiBJUOoJMV2c zoFYokUlW^-(mTW)1A$iuE$`G|lWdK3Es~^ZFNWXZ^D^6cyf>#SF4nmM5j%;)u~e9j z^kTHaNuR)KgMV(7s)$T-wloaqNfvf#DBDw_)qGBjG^5Y}+hFGQUX6`oL)C23+a~-`_Tx$P@<(JA&dHwd*dpqX?_ksK36~N zR6j<@lTMj%yMkePKOsu~B_cUiL#Lj3{=Lqo%gO*9!Y{+`{ZyH&qdpg!tF2lPMS zbRs#x(Txc$L_XvUz{anSPjo-n75I)4Ee*}6;@I?Tq>E+L16gT7y4pR+)edDm*f4zCq>px|3VCh zWuglD@ps{$|C>3W+;OMg`CZa3q_z#|`p9AU4W8SPG!JBwV4xFc(Gl)|L?6={XDEpx zJ{!Y9lX@;-Sg(uQ`0egHKkwupucx?oAoRxaMcpgMGA=%5RHPdzfIVSE&IPZf>!nf8$ozh#?`EG0U74Ud9ehmJ_ENs4 z$jm`6;V4QjRB)%C!)@Q*eOrICKRnv-qfG*04s~v>JwQ~;=n_{+}Dg{^~sz%a| zpU>Vq%X~;e^$_GpZX_lFt-3en?<%`FILZ*=YuKUoG`x3HM0s};yvvMzN<0*=oxwhSe^|aMpdj%n|PtW$q z?9YI;4eMa~u-_f5=D)1|o~Wf}wRAN;+(?JA0oJgxH&JyVn8RocNy#Khk;#K!Q2KO7pJDAR^m(jci3aMc4H#3RuV<|9?bTcJQMqE)l772K`e$PK z6}pUh{a=zX`DHuP`4|>59>29N=jiOdvMaXoqDjfi2dO+0VsQvEdrc`PD5=vTMcZS6YRk*X z_KO6TU@@_4iI0x@zW)bM>z#qNF(|j~0TdaJM~t^`8r2tz^|*(_C3-EiUdz9ex+KR0 zF5T5{hgUkUwxaxfVVLHh>~?m)rj~>*WxV+Q*vp7pT4Y3EuPB7R#Qb!3R=*ow!d}Wr zf0(EA)+E{!dd}X#8LX;0`n|38ULiV&yE~a?g(Xl%rA%R0OFk%+OF!i1=ImJ&K~`2) zdu-kEL4hH|*|{{Cy@%T%UzeN+FrZ1GI!h{?S$W zoshCZhO3*|OHoHROecTFes=elMP=A?6Pb)*0xKlN#=mX}^LjTDb_WIO+DG$W^%cmK z_1Q*}%RG)eBgv}DvWY=i$AVv-DLM~`qnoGj~bbkY>8 zda%l#M%FDu&Bu^4Rbx0jn(dy`s$GP`x5ca7ONCx3VC>_~%{xx}zHW((zm;99KAPJ9 z0C`zNAu|9@cedJ#4fzJfC@_cXqSHd5d}U~5ds+nRef*OXe~poq;uDhQtR%;?q5m4` zsd^ldWp$qa5<3fze%XboxdZBWuT7X_I1R)`K|9h%P_B{?Usbe~&VPw{v~BwxFCU0Z zCvr%-`|me~x}}XkoG9feWF7{mKil_&IL6?yjie**xR7A^=X2&>x#~|WioDSPel2DI zy|i+&fle+6i_=}3;sysp@&BT$1OCnbkHwa7`0tBfb%%Lms}v>(MgSn6yDSQj^M;D) z{pD*N*#(m4$v|Ffj$yhL9LjtSwG%Cj@iJK+%)u6RnS5KL4Z0{3aeNu{Y(Rs#M>x#D zk!cy*^`_u!_Ufd#9C%}%81Effa2LBt`Rl`7@A$eT zsN`;B^D}wd_xp4&u|%bm#b_MJNn=hBak^R7E3Q8~4ln0AP87^8zPetG`*Qida0 zvlfdRChZx%HzT|B6)7=qn4!pPwKfGEcXT%9vhRW<^VCbE z_>i2?4uPY)kt$e|t4r{)#nR*F!h}}YUV$Bly|Z>#V?GYU6Ea6Cei@USK4B8@+i$G< zQ7~|)IEbD-m=doT;>IexhGQEZG6C=w;T%e_VeT)gXS(s?N#i?)eO#(Zj@vCtQ2neZlWBzKbKdx#I;^df;8$IlQ1d){xC=|QjnB9qYjsyOuSZ1Z=iga) z1VjWazp!^K9aRY=v5T%VWRWcQ@F@X~b|U+r00*;5P1?@-k4Ytq#)aRd-YldIZhJHa z1re@w!CESFjHL=FAY%j7;B>%lpEXld`6JH4H4=+5(H2wXUG1K*jW2Fh^d>uT%Z+@Lb3%Bp_EtiYPV*9r!tem}{ab=w;ujq!azw5CTvU0@#OSY&tP*-E zyCc5cRW(<5b{ticY`gv=indgdVbWEC+&A=`8u=(k{|0jWJTXDMb)HDdw6I+%;LsLK z*ZK4tkvum1ZG){<$F_C;KPalMYntS;i$;{;l(wZo?gcaL(WERh+ZGCUeR4Ax?~fT^ zpapdGo|Y)IxlF87P!u~4(UFs6W(e!gA!5V_xx15~dy>ITtqZUEEKyw_hv-e_tHB!Q zlR{lvQmW`lgXpGWdIETw<$*o*X=@Gk!xX$aFuO^-D+6u$%bK;8^mo@D^EVj~;##!r zXRIGd`{8BHxx=R>8=u`eShWz@_qbdjIv;R>ox8_-eDuU58&W+Y9nPA-ZRM)@tYB;4 zAK(qYIIWxq@7Hr76I0lVSI&?eRx>ttIVvhll=JTV2Ki9B{(|vJ_=R@gWB%NI;kK>W zhW-;+5N|WY^HBBEx2*!pfO%$utm@;<(8&|k6LFFGZx_wO$*`H6VL60Ur8mu?OmIoA zWoGTb)VI|K>HE~`Z?j`SPdAue5spm8i*nE@wR^L~3;bC7ovWX=KV0e-*yRWCbbkhA z0dPNjEc~r3n10;Rbw0ksFizo7X+q@cF-vssZussy1G-8VEgU=-OJ@OWHKg6{4UQE@ z{K>zP^1PyA2qXkB&!Cx3*hve)*(2%pGrTZTv1|5v7oP5P2P|Z)sMi)(`inMqZtd!e zX33bzuiBo&lS!Y?u-8}c&ydBtb>H=l z#8#69trEG8OLpelA7A>qF+LeCG*-mzQ0%5E-Rg&LA+7NxQb&5G>^i32dDb=H3TM>P z#=ClPyx>sG;@lw!Tm;l-=BJ;3;cHgExh4S#kqxeyym4Ua{e{{P&la75-L~%i+H8Bq zJa67BCAdwenFEz;Co86`%ff*4>gx9PmKKDQ3s%u=X-{(C`=91T1?dQmW_<~F-1_JZ zc_wmY)LE|PlVc(V_Hr;kroc-x%ySaBwTm(jVVVe4%wVK=1El06#*)lSQ<7=#YHD$J z_hyF<`6|LavKIct;m~3qM+B1BomI*k+fyhLwTRXl>CkUlVT_h%tMVld?m!~r$g(Kw ztUKFtpu*Db&|LE{ycqWZ5)zwB9tJ-#}tJHXljYx4>Q9O!0O7E6BgFcOy zAU7%4k=&s+f(fHzk^t{BOT#mDJ64pyBL5pN70-71voE}h$PU|Yaf4cFOg)L%HJX=< zkAvy1w!axA)$^%rVl4bq86R?kM7uu*sPbM*t&^wmd3LUDoq(AS4%6^2Dn*{7SI}lP zB`Rs(@v&LJCjn3Jv2|0GK-4RekJQh_vU2Hjic8GtF`q`fF$|0^|IioDZv{0AwvbdV zrAKAM9+!-DNN{S$P{K^CG(3xesC<$mF_R`rtoQ&tvNi4L98U1vS5ca-q(jRW^)SJS zl`!cz#*-3v&dboBZ1s$?@2Da?J8=z!B+CB*ZmsmS#PO@}f3s7hY0XolZKY!@_g`P& zxuvTejeN-%^tWiSg#qm?5jqrehJAn21x9%yXV+I;Yf~XupRDqmNjrzP+Mu`bU{#I48ymgK08pz9qggT~>_;QH)^F zaHed=u7#PG%_Wa7*@@YF8Z|vj4DNbe>yB`9#mr>PdOw?v4_A1HXj6v-S#X20Ad-q> zM621B#fWIKocY#Z>`62oSq{ft^e))_OO9pZ{X;G7<-jc;4-vk_8CKMW(DM*hybCvv zyv8~#6e;8S#wEKOQlC6Qo1(nlctbNiZF77<@rMo~tMjn~o8?NH%)i7-VB3_glvO0} zARWN=W0m{>`WCxvD8QmPe_u`oW&PdZ6kTo!BrC{+nv^}~_v?P9c}|7j^BT91jFfTjhL5>%ii|M@S@-K%MAz*rI)bZ7CcOY>#U-ib#?TBqGK%OCPgmzDn}0FZWcDDy1^mFMS@r}DG{r1q zJISlTSvUw~3y^V@{}GkFt1|Bo^xuz2LzGp#gK}5 zsTpP);@iqr%f+TK@J9bJ&87xf040^~2a@-O9H3v2b%|KUl{t&s>e7Uz7DgDGb2w+P z3CnHr`aTb~=5pTJkg_NZ{H6g*mJ*zyY}^$ast6yJZ^Dt~3;qvN9Q-;T?~8cRpazd- z>dEtkaPNI+bR_Gzz-I8un2Dlj1S0{F$q{G;t!Fyg!2=MTtJv+P@J)b_t9C@*3|Ow8 zKOIpT7pt4JDS3h;tS1P7?z&um;hW_x==l~9Ul%QtsgkN6KAo#r#eX|{Wf_AZ zgZeeHmg=*u5|n_s4bAmbglvn*{?xsN>$Js`9%E{m#gZLHSHul)KB-V`6|^~jddRb;AAR5$avd(XJvl*dEZ)- zxD(K8?Mq7g89gy7p%ZIW|4-2z?kzfH_Yn&&v1*TR9MM$Cp~l`LDL9gL7$%bRS#@tUuXGZRAZa^o)~^8%B~@2?1TH% zSyR+ErDdx?c#Kze%E4{8h)}Z6Kg;eX*A-Nl3O5cCN-&;_k~u}bWYz@CFqT|(m%nLr zJsC}~vAx6_wurG9`og3^PP@kQ1>k(K{24bW-VquEt{ve|FRzzfyf6OK-6f7OIDj*~iuqEBg?89n^pu0ORhg0uNB?oO_<~gD@DAthAON#d0iTjqT zrY2^(D+L-2l+Opdt#PX~uo5cYA3$7nkd7!RO|y8&w*6*X^|_dO9i3XH*|t@8V^=ha zF!l$a+=PY0qm@UQz|0-suofE2CI=8#8Xz1>OBy;L`0?UP`d}68P;pO)GC_m5jUxZV zIOtr1ma8<2m&YW{jD~6=y@IzpHj*6cr@9OgI<(XOkX2pM5Pd2+sV_~96T0)lXA9nu zB*+RWaWA)flm0Wv%#E##PQ9%$VVzZyZO_WQ=(6K}kshJ@`Tmz}N>1_a2~mh^|15vO zk5RxGb6g@hytHOL&wG1E73)yA>yGYpc!D|9zPEE}<|2BX z<5itY=wn%v6&;7#)qVbM%Mh|$BQUklkOd{ON1009c@H^k`rYPu!(_{gGbb~4QME%M z77+BB3g3=qAW#@3;29gLUU-o8e4C7y=v#(6_Lt&8sSkc^a$bt*T(86=#91;F^h&Oz zVd2yZNqVdn-%Z9FG~~R%zEPYT;76M6(ua2>DMw3`Wk5q9%{XcH^GL0Ru>|?a@?+}W z4~yc&sYPh>{Kz96!>Q^1{^4dOcF(PXa&#OH7?ufb=3x;F`hEAbu-o`GE*m0q`FFGH z3j=Gn)meq=J{BhS%HI#;G3-^4_mef&MxoF1xC3V**(K4A2%ev|tlHUf0)wmlazQ30 zeRQljjJ#Qu{Mh$nE5YBqfjwk+|H(9alSMkE>=J{k`Wo)QkR|!~b`e^%%BRp=_DdZY&ZmM_sz45pe88%2_mQ(M2c2y>F=jm@=tJ}#ycb6qW{{TL* z%|-8as?&By{jNH@FLup!BrVqwv&37$o;0&6mg=&#AJ=bY-qKd}VA0M`HQqSP1e0ON z#J20CKloCY$r;D&|KPZ&gvdWjGSq1?B_G=Ujr^t#D0oYwfC=ErDh$rN4 zo?;F3WddKuXnZMBfU%gqT`;{7WYuJLMxc9a^dq; zT;`F{t@3hPeuR1A^)+}D5@j>Oyy6u1X%rzCJSTbO9k`~rBm545*|4TOUM}j(%FC`8 zW(*!oFmYElu09_*mA0`4s_QSgE_m1(ZIex6FG(u!7i z+ixelQgEp^<_u1IOQMCQ1G3<0;W5*vhLRNpNXJBDDq?9Q%kN>yokJU8=!yRG^*$&L zp)K)U)IWKixT-I$fp8doUuW!VBx@mcUX+|I+Tp5mIbpmKNS>56E6RAMo1E<{?Wy8^ zKtnJX$fXzh`u41$s!9Q8I)tOWX?*cft&>JXnxQEhEn+t^DavLF$PI6<=zD8m^5_VZ zM<}M=za%{KKDA^+EFtYnjBTi^*Y!RPlr^&TjJ&tsD&f|88A{BjJL#f$hFx-8D|2k^ zFNC@`v&_g*1`90YrA9LzKerY&Olbn!u37pVdo(vOp?u4B;~1hxBr7le(6q+D+SZ__tk7&e*#+D1Ap?&z5wkTvUgu)PRj}z5jNZ4bm-_Gsu+(`@A>AG|P4# zT^7dY0S-|EV>tyn=COUR*cxLP>v^zM#+{j~_P;QI$K6h*DO z1yWYPZ*Chi^XPowk)H}G@zc<7$F5l$!bb9h2ZwzwBQC25`*872FWjWbPbrS}go|v4 zzGCxA$=SOm7CoZ$DaJg51tqZ!QK1RmXL$Jo8x6)cLbN4&O9_wJC`_SRcb9F@Qi3vR z+E9a-FGud5Ir|@Eipj|e{;Nk7?o@+0GALZ)=pq)jk)YS((UsP)M3FF5JLj&R3<*Q5 zWTnS@5~Jo?Xn+v?jBd(YkiSM!Z;itZHQRsS7FNg6U0>`otQsoPTbD9)bm5t321V zSnl(HOo$UhKLyl3mdmPxh?QD3}FV8()Su%*6mfxi$u&zU3 zY3BHfvl#8GUQpQ!xhcM%&d>2ayxgW6+JW&7*Xc2Rd8;zkzV-@#{IvqC>$;&H+UttHDY_N1 zYTiyhwtP8YG*Qg8?Jl8Y_e59c(#z!~bz1M`^ff!K8*Fk4OO~OYgE=-ui>H`r%unL8 z=Q~<3cUK@fSEIP8(Y`wBx2^H}KLzIBT{nF==07FP9*x#wuksZ^13dv`XkCbqWw_jB zv92lhjig3PT|JlOaVMxecIhIRG0{&HhimwT~x6DWZY$u36a z*5Qswfs?s(Z)h6T=e7!$2ig^tcy{B4MORbhc9BCv{Pmgi_$ zxVWH;TAkZVBHMZPjhPfp-VdML{^q=@fkrTi?plj(cyE{SE)iP zc1KRsImCSiL++&S9nGr)i)JN73**ajO4S$ehz(leWDO#*jyiUWWSPM@%BC#MeM9|= zd-hDIYXd8v;<^fp!@2y{Rpn=Q!n6@FpW!^N_bt3wBS3=LGkmyz0c@O|=y8@Jn_Z6# zUs6<7CD2r9aufnaV3yDnIlNUwb2|jdEEPuLlt4Yo_=XM2 z_8Ua;X7x(iKr$fF2RJ!Rhi2;^;UBt!pWQ{ve}gXVWCMrVS1G!RWQg~YBpH+8qt(SD zTV))HjLL2?4fR+fpcx;~A`v7Bwp(PUNRZY~)H)uxAI=*G(@97$Oy^w^yPK;y-^=Z7OASNQ?KW*qN|M{qz7b@=V%oWBPM`dY4r9C~`sE#++SGM9%l zY=C@M@w+qTiqwmk!4Fy{808Ou>g?XfIimFk-+WuI-Ou!?{nz%qstNKPwp^C_z=KTnBQsy@^q0q!c55kqEPU830;I zm;D&c6sl|hnzivsvCK=Nku9^j;f zyeMZSx4NGB_T2VNSr=&-d(=EqlQ;FHP6WhL|Q4>8$!~31y@CE zgKnglUQ|TxpzAqsG)?Q8)tot;<5LuV-{{DwZhz~tp#gnPHknZoxcmx)A(Jg4=nu#5 z9dYS%{g|~AX77faXaLpmEc-PFz)#WaeL89|b0wOZ`=fm`i?d$ND!P1@4agMwv3<=Y z)xf^!)B&}gdbt=vRP%I1v~8zVb5~~L%E0(bIH(9NT1FL0)43Cfmr3R!jb7PN{yp09 zq`)2njWGggI&e7#D^`R#0m1@aftb5cnK@_xPgaMb27OSOAW$+!5)F@va1^1?dz}6U zIEnFR`spH~CIHmI%n6hWO3MwB#Df};$i?E@#qs7TK$>&d?7>dLPf97yiEc+uCSE%Q)W01VFxi|U& zD3r-+uQP&RAs>G;vh%Il({0UQE!87PqDV1`ZR^~}K^@3Gf*cmwF(Jq?;=0BR^1vu& z4^^bbL=M}<7OMa%YTBeM`?CjSk3_85=_qONXE7K(vChTJTtg{#ZNqIeet<(#DZ=cC zkK`SDjTQ~snwpa+L)SG*J7eFjeIwYh9*&}+6%nGD9hgnMrVwyrMSafWAysW>d)f&k z@9PtTCekH})_vo_kSP1I?QnvzOD?LYaNRFKX0qe|!U5&Ey4_&T^2qvP+8r+s6k+sE z*Lz69+8BB&RmQeqD!t?}mMTlXq!Ec1(`B`l zxZ?G{;yv)*aA9e0Yv<5H0jR@jmbXEhUoTQ{yPOhuh9#D`xYbV3M25k+t%!D(Pcc@~ z49Z7leqkT4u{ZTFRSb<@G0u_RIB_)_|IG4I$#RB%Hz3p5xC}`t7_j^6s)Z7{qJYNa zh^1@cPeIn5>OIz&V^3kOLOpBo6FA8bhInu^BROZL{xc!Xt1KT+DjeYxbzxE%C0^Pe zx6hQT?NK97d`ZV|)HNiNz1b%BO)G;K&nsNHTrDguBY>6b;Ee+c)3nTidm7JGh zMC#nX=;LrW&{axqJZ(qOlCL39Z|b= zx#u#?SPdcI7jO%z{s;KL+xIq}&?+zRZP`q?F60$qn#bO-SY>>PGdek!EQ?jK!(D#0 z(2F+|Ta^q8a+I~xAX6(TmT{BZbL+7!Ef0OWtFLh|mN4Yt71^SJ6_J|)IC4>;u0+?YfiuJjpmm76b>ZFR*)z9_bm|k>g2q$pm5MRWt`jk zogp767=QcST8)7!odC)rkBmiGjkjNX&<;w|k{KyhqDcpWD8D@M2OH9J(2Yh}t}7Zv z@|xZf(BgHe98(*{5(HSJ&LBF7L3)KeriZ;7Bhk$&{#9DAMLU@A`vHyORe=2ap915p z9SZ*d{Kd-CQaj15x=FH@2OFI2B1#tx8Fjh>-}wIlU~F9fRjaT_!vhU9?I3CXK_?Nf zWfqB-BiX>uu-KF9G@|fPw-3rtj3H5x?2h5vbdVx4amHUk7T<ji%H=#;2F>KI5A6c?@s1%^b^NF48rA`_n{(u`fg%1Df z=L2~~!>x%NJl)BnlRrW3lns_|RSWUTmKKuSNkrKVAxz?2Vm`6sw+I;vls%p`MO>XM z1xDwr>Um?lVG`*MnaOUQ(!kFcPIX|c=N`0diu}auyY@;BjaZb9m6EL$`X%DBbE$qy z7tm>(6yRn)Tl-fKbMLh)6|fo|kXy;=$l=r!Rd^i&IxWg9FxE0;Q_9mhW_U?TN~s#M zR#9;^Zl@W|%T(#CZwNg?DSW51>1VYZD>ouqRYSRUV8MH}?UBTBomIG?q)j9HykV*z z2@omOI(#Ev?sPWUOa-M`UcqrYn*X%&J^^|E{^(X*3}&bqVriw6#QSMFW}MT_hlW{|gsI_$#R$SF=9{`~#j;fy%3BwvI z@+DfX<$_h8>Uq@(;ySam6fa+_|d40i0i$MrE!oWkmc{mb2#364?>x{3~h~usQwh zWi#jeD~v<~m-koitsYnBT+ZgJ=7usIwRf8G1N3eQ3=EQ@Bd}LoRPHsm%{vYbC;GBK zGtOt)XrAEKhIh*B&$@?bZD#~he}aeT9;$ihv2&Y7am}Lr9XUbY^3QjsH@RN1&Z1?B zlPBA-?*`A@V^2HkS5DtC&5XA$ye72Ig4zbpK5y?oD~Zxu!n4eL_pa@=iXb~$Sr2xG zVin08OLsB}8Sc&`@@w1*Nx{j3zp%jAlS-l`ko%B2IohG=9RSQX&)WI5fIp1{)4|(N z;osp8y5g~{9grw{nFYH>*=C=nqkYrU(vY`Ff?0!dL$wD$t%S<3d#um>$g9Kj!XEGK zyB6L3VEjqdWcK-pmVh0cJ7%A*nKBDCx!%}ZUcJuNtL;;D?~sYA5a{xFOILhOUecuc z`p7&~#KYBUsPKJ9@GLs&R+afv&?VW<_H>Yty!1+G*=DApyqkAn3#STUh|NBU%0pl>+mAsU)T zL$l`NO^GEkZ^g4k5;{GC(6z+T1sziN>G7XQccOsw$syhg#9 zHt{IoYXUm59m{FvyJs-R!L4XslGSR1&n50Z_nf*-8#x3YG;{7smyKi0V5>0Giyh$U z74_&rYN;IHg@1{7b!#bkU&|8L@g1gwjlnRo3zPi(yOKSE^!Osalwrnv^@iYrJ$SJ! zk(pb$sa!dk57v$y_t$YU={sit2>Nj~smi{`mOp0|#9cmzmx)o0se0g+>4RoNlUV?# z8v`<~0+uy08%^Ynrqc&{{sAl>4YIN!vgh`rE*auH?CxQ7Pg_;5Zn~Zo@|?AtksG#G zoft5jJa;{d<+7}-TiAk5^uA8Szs$t2Or}cH0HP|vnD0kEMu{&Thg!O~d$#sSFKtW1 zu%VQq?s`iK!hBUzM&=FN{?v_IHTY3_aibVu>qnADf;&}zwpF8VNx{6l^2tl9Dw>RL zVZ5&R{?k}2c`P0M8fn$pTi{?=ogwpF8FTXRgmwToj8o-TFD3>>V3DXMP9k9pEFtAp zIO`=`*!eFxNbw_mqgwjqy?QG@%{r>KK@w1MP7ah=9o!J3M&|+t^yr^dq%_iX?&v|T z4ZBx= zqc-s9&{?zZLo`~if-PqDIWIdua82|fvyW7^=OZjeU+~U5Nj;n76k`*AkCWedk)&?W z(PctmFM2d{Ci@Pu%;--F$j=T@+9{WxkZOhD@Y&;%5yj_Zog-s_Snf?71Hxn3WIu}m0 z=WJOL%w@$ma)-;67*3V)YVby8LZ`yp_BF031C@{$9u2dlEh(Wqn|bb3Zwvy-cEBv|r2uMP+-jyT4A0t+}Idb}0(el@Fsk ztM2ixzLbKZ6IPUj|>bKAdp2$IHz)as;~Kkhrq|V)7l+n;8v9f7i@( z%xCUU?Y^?4hZKPk!s7W(02VwRIn+0ukD>R;r4r&lISnQn>u4skQRy8tG|3s3Xc+fi zA0Fxt*?-$oH7^T|ys|)9UhiEc?s~mTQtQLM{d}&z(|T6dE?`4RIL*ekBxA0Ts)>7T zq!6JnlV5j-_HalLYrF2#l6kxCyOw>$9a&`&zv+=*f2hBo&KtUkiQQi|#m1=~W76SP zGrX(&IJLLmS>Rn8BCmCFCDp*I@AC4eL>8L8x}HI`78cg_;23|@mx7YN?ou*}a%QDD z<9NY5uTPLsNaXv#v3aDIK3d*NtW?FxZ@8Z6Czf$6gAhOY6mj|uBmrgD zjKnoNL{lbvn?=#+q=~Jn5Q3wF@*#;wE`98PG%F>uB>&Ty+x7W&8M8ZF%mKhYj$fkt zslLr?bv_X@Kk13Xr}e;w6v!e@mF!J2F=qMF=({MWjLYg6GSe4roH$^!uE)-{w3?8z z_LoMZ_efDBXx2H=lQ{CNH&H_(6g%lmy0JSSSjjA!Fv1IydSj6GJ4#}^@G80& zR&9)U(M~?tv_y{TNb{pZoWxxv@LDWZ$!a zZS{vYJxlAt2wqJlyFHXU;s!oSJokrXkXg|vWF@P#7yjKk)P|r_5lrw0e#7$o)bmFuMA{ zrKwbn{$+e z`S~Pe@1)-1t6aYtW>jx2BR8y)i+>F7l}75BppcHGD&@sV)LM7^tF>;{Cy)k-%D` z7VBq3Yh#|Sr9&21pfZwoMaQ6pI^gzSS__z77ss=;Rlw`CT-$~yyILccesN}zdB8Uh^5BELbY z*V!Jnta#HiPe|_v)|6bZdarre;dJ0%m31bp0RpFc4jBhs5r}wGo#@J06%9h4=av1z zpuJ&UJb6X(o>{&~3p$mzs(1LyQ|((wI+ZilJSkEt2FWCdebw26hIj-h>%1J;HTS6) zi1^jbslGPYFwR*nP-<6QjP1(CW!soo{C+WwW(2~;yI8G5VG5#b=Ou1$5q53eDM3-? zy!=H8|8FXhJ9@lC%ruStoK@RsKk_Z$ijzq3aM1OG+7CTe_p$Oh5sU@n2YWrPSH~R- zSn=UXe)W%+opaK8l7DzQLWG<7DQFa*73lR=uh6Y|^0YtOo|X#LV;WH%n|%pn$YtJu z=)UETU`EwpeACl~4`&j-=}u}0X!`$8j|$g)Bq|3xh=O!8yHO{dvAN1@-D#?buDJCO zlf-;+sq<}+jJzPXlOd$*xjpCaGF}XMngw5i&IMRQQZ%lh#&avhJB&H00HPC3fJ*W5 zV#(E8WN?bIMYNJAygJJ6LX2iRD9eE$8Vy4gTytoTq4FS#_0)}G@LR|?+#xU}0CA@S zTQ55cqg3w=f^eojaqe7iZ!)#RQH{ZxVNnz+gWeGg*S}q8gpg!p@Z#hwd1)9;2Sywp zp`imccX2Z2U01v2A~c&})~+KU8D~%{ZRJvdg~^5Hlm+I%y{GdM3ojk+5hgW^`COz% zDQB_ZhCuc@3%_+Cg0@mr`HtjZTCx2q$qZH08F#GWWX)@ocPt0Mn_OQZ_v;`(4%nL4 zwn2RMKyEpqk`BqdO&k`!WKazzTTuE*%tB|QC28hURIj#q1?dbSG@{)tNm1%Dcv6KB zE;bWA!)g!JD8{>R7c%c^6ZE84V9L%z7`x%!wYp|L2jrv52WWj@wgKKQXh-|O;jfk< zBxJNMy6r`WeF?b#83auWplnmLlyXrQ?I)VTK_n1WyJ^TsDO5AN!E+i<;Nzi+-JQ1F zT8hsb%npF=$5rpi)J0>2{|ZWC4cbtTO;L4<=@e}i0$Y@;?DCIN?Q&BgVW8YMS&`>H zA=A?E7XCar%zlN{R`xA3waY;m8zOk4a>21y%@dq;~Q`uh-i`i$&TysK@; zA@B2|qYD-QD7m^HpQkQ@mMv6ms4s&>S8LI&4dTp{(*osZQ{*vHNB zx@krC$$7Rp3tzRHoIbiaTuNj~7gu~(3JKP=!z|M>n8e8E`&js9>m2PJ?dgFvNWp@f zN|m&drljNV<1K;ffY6f?2N^4(D@H%EZLLO!YI4s>&v0GFVspcA^yy07;+v;_V8ou6 zg?$VON&j!v3M+HK=3=-KEl2o~8?^H57C?$cNvT@8B(JVy`z=YkL44&Uj|%doTjYiz zBYh@A{NAQ-mw!j1&zD$>xUW24NgKzOuT^00KUR^t%x%ag_CTvkWup-kU`o8?{qVl! z_a6%1HHDF_WW=Blg9}3O(b$(6iW&=keS=LKgv6ICIKprQ&ulc(VDTQmvsAM)-%%T% zrX`c<98aWOA2i$~JfGdDP>mF+y)jU8lUD#1=@CJI`hF4*-eG5%Y!&4 zDOLZEu=D(e>wUZU=$+BaAfp?-ccS;vd+*V^Ac$T@?=|}9M2QyBJ3$yVh%!R7h#Df| z`^;bPd)}TG=f%C&IqSamwfATL13xpV%&DRvp_>XtEb1$8KLGx`x@{G`eF1?_uU7K5 z&Eu5ZPt}z)qca?0G<$np@=A0Halm9nQJ1T@2_=jtyj|aTh+I!6jtmDTS_-NDN0c_g zSlJz8DRqQq{oQ#U?+CY{60$^$ymYL`SJ$2aY(?-$YSV&DP%E=`k`KO@nnW;N=~AEC zf{$JG*riIY1UhV*-fBQKpn6Q@SQmX`{5Knhn0JaMT~*(TqUU0GUY9I#)pYFtsr5aD zv@^SGf2UNv5}b`?`?$Wq^iCr86qWY*_WY9)Sr!I-v%-Yu$I-i$g|4$5qE8E1FGHJX z=hJ<8i}7704)uZ zzqF&jDgs@yxDz7U+E*be!PMx|Z~(Ie2Fi(w(fj%@KEAtR~V|cKs z80P72?uPsa2)tTR!%KPFX=0yA?388iH8}Zv6bn?GtB;#X_&w0t({hUQkF5C@K*tP> zaTYMSc?>n}`5F#?qeOgghNcA+k%@3oFZ)^RE|(t?1Zt|@;^=-qjbOQ;P%m?I-E1oO zn8jRv`MYqsi~b68Y6Ym;ukz75xKxM^zTXa!P`$wdzT{Xpi{9Z-uMu3ZS;9#>HW7$} zS2WDLn+$`czy$5eKxpR6GoPijaTFWKlftvNwZ|1!2!d5_-nScS>+sI^4|gEHku<)6 z!*o1KMM@?M`X7#AsU5!%94L!AMPGi-DjNhZ?Uqip%zVp2%eb@!v&r-Sz42TlKL}b$kq}CDT=t3~+o@`GWzsGTNFi5Gf)6j!{--6y8>GLi?{Y&A&bUihGadG{Jo{nwG*| zSU)|i=7{$E5o)m+1?Fxn%QX@*;`6MU#0TRKFpMEhS;i&l*J`(7BHd+ur(Ot5S|CYK zYb8|%o!Vr7!N?91zddiF;+s0G8{07(x&RS>!#5s;O1r83vm6Q)I10nj)Clf;sA>ca zzA-qKUeZ=4{Fi-KK#R)fs`#9-`<#8!U3>EuW$HUrwoR|<^|GF~OIU5l^nsaMv!5*e z**RlFFl<&Cq|(QnbNe&&5SH>x=d8dfp+zM7>;K;cN&|wP4zv;K67Uw~H{z z8iYHdzv66asNWl~&%UZ$u6FxMxifoTCm5-~#TpZCH~hUZIr$-}bM(!m<_B)rW!4a} z;vJ_HKYZnsgJ(F#;V+3siGO2y&2xF+@yTG^n8OXF1nKH~?Is~Cp%tS( zttzE&VCx`d>^byENRc$gw$l!HLb=^(xS<9v0i*)aJ@>bI*=eu37L4=OQ7^U1oZ6+p zSv44y^r^qQ<|#gSB?yuPy{E5XvH#Z2{KS$*DsrzSajg})A0uxNl&J&vq1sVh)mM3# zLVpLUZg|&(1p5l^_~=*dV(l?Z$ow!81``y)cGSS~O_*g&2}Sy$pE84Qd%KX}Rp$>w zb-l4kBM|xd{{Z&%JWe;l20c`S3K}{_8^ObaQ;R4ko6~FfRs`>GArf%cqMV%0#>OuK zyb6mNLf>q`d5%q9%{SOlY@>W(ah6T`BAY*cUq7z(SL2trk&C4QXx5*D;puDRHUecVrtERE= zgs@{~imZ`Ub4*{0P;E{UK!VQjyogye#LLvWzLBf2 zUPzPG4$aAJT4}VgYF}bw_0I#pEfgA9NM5nDVxqCD{KjVfjgXhxNth!UujdU?BYXdm zT^WyIc*FSuy>{J&`yraY)Az!GiUHe`HPiyfciF;A%;`v)2*va9)0OB!TUSnJq}QH+ zmay;6^ku~wremRI;#XyxX}86(m_yMozURjmpmmJM`G(K${Zc3)vETj=z}1~=1Y-)o z#zA{O7-V9Uj)UYe1lyyV$hWZ;U6wE$O_l_|`=bg)_Nl>VMtTvsB{PMni+25?_RkR1 zvht`iC&bE92U}3WE;mg$BJG#Ac>RIl4y3*nr=OXho^u`Pxx$Qc>4fM{N3JeK#4%t?)bbW$}y}Zoo|5BLa zQ7l^al3XrteBbvW#M~mYUY*WE$c23rfHSzc>bEd2Fk;`fVZ`Rcrcza;Zau?1%o>He zKg6U&7_>7GStkfFGYoMMI2tYjr~UH9B@@MTYXSA2U=MOQ;&x~W787T)o`Jb`ew2Ku zm0Kdd3Yl=&FtD(f%oWubVjxD2Z)FZ}cRfi|AJ9w%s+m;)bL(eVI>Po;evywUIMRme z*hr_TG4=Z^1Q4HUaekAq%a#a3GGuWm z0nN~8R9VKXa4A##Bj=7f+~p=ZMwcDc=MM%S56gbJSTkInm9lpt z4Mv>tVjZ;8kI7}ydRMkWE`0{f`ef&*NMAMkT#+{p@UVIY?v8fe?l)@$9#M92%B4yN zfHmjH@PGhRRB#(rt60t_^sP8t;qvo-F0!o%^@fJ$E5vu?{CTj_|{ z;oF+?v9D9fD6q4P>9?HrOnnyJzQo1Tq~x2Lqw>)%!N_$EzG9 zu%CHpNSq|H$bIvR`o1@1>Br&R-fUV*6*@+Mpbg5mj`Za8r`6*JkD_Z?YeE%dk)42Y za)0^F<;mz}Yq1=dgeMEGUvFO^>7)_1L+D8l9pBvcNg!434pC>vo(YPNGESzm^@}GJ~gBa&qeNlaI;SM;kMX?{EPBbV`~|KW1_R8TW{EvKw(= z4Ea}Pikk5YCl-HYtK@}sl)9EZY`?x1KEn*|`4hcS*QvnFEA3_KnnZJVfMdAS{N1yN zP3-C;la=ZoX}SID|n2ADuOYr5oLhSYq^JXlw^dx2NS&fLcNlpm+p-R>cv z_N(ZLr>^F0g=Q`R6uv7FC6}|~E$g<@XWl2OKDIwmIxd}y>uy9;1x+OfOnUDdd|yeR z@ig2p<|j%Rkti_smsYa=Jp|0X&oXRY`uq>;ieOfU)y|}Lcpbu(@!;CH1(e|mD%QNk z8SdT5_s!ei_M)C&BP%-e#UpPHO)m8cEDub)U5B@QG>o^a@Pu=VS2A;yeq3%5aoN2U zuVFNugLoaWYZ`gK>Kp4*Z&>Mri49f%8r=QtFof4xs)hPV_3^uHEH@UXwwEvdFlNx2 zHuM9fo31ea3sI43bRAOt51=M6@*&Yg6ymFr$(n@Fgvn8yHi4&5JP;Hg{JqGX#uF++ zzUDYuYP3xLkKp)6k?F&0UUL&ZD%Lm7ci1Hj^d1C-4;8WxnVLya3{wZd5zu-_f{aFPq5mj}Kl2@}UKq zD=!7+a?9*e>q~!{+Ef1rs2(Ee-w(Sg)z(qYuCXj#3qR>ws8k)QeSzO!HpXY4pJJ_v z&v2qIS5>>YWb_{ZI>>PRJ*F9d+ie;P5hlJkhbo2%G{~kLi_{vV=MO4$!Cxg`#nR1p z0DIL_h)kdo+;TJ%c|y;a_Es9PA$mVHIBsQ5-IOAipQDcx$U5!b{KhNmQkE}4cZ%1Q zxTgITZW$g>Ms4^6{-u{f@A0sDeP~OntN2 z14iYe;QLQRar{C#Y+BY)JF`NL&!kt4sd<+qW4-slYu~R{Qf&BO?yy~cM6&-|#^ZkG zbZYWwC4XL4&Mf#eYlc+x;ETtwB~Hz&5Gy)c^jA{1=-)9L11|>j_JT1pz_Yky_^B2kk*JDb=cbX;9#s#K)LHxh7b1Ubj1tf44LG?E7u z;)s6QGgNx9l^Y{vq^7`OR&l{w zRpFLd(s)q|;~&kj3<2Bf{%W$52A4%t^yF8K=wW^Bch6~0ya;c$IdrPcp~ZO6MWmoW z=)AIK-J|`YnaIo15 zfGaN0?&;L-nFC1hdM|d~pSs0HUXkn)w_p`mMUbF5(=vjAWXjhKeQs3iPf9yDgjW)C z<~+w>g|to}iS+6>>lY3~6*OS7BOEf5?HK~ON)7V8a2M3)YW!kxA#EJo!N}mmFrUGT zQ(1d@V&(CO{!9*3`cg@R;q21B|C}SE`gh)@(aJ%oF0#_B&bMOko!21|uB7qw(QfHp zT4Rt|u_6jITp`PO_IG8MtN4r9pgb zQo4`Ah!D&~tI>wZWz>ASLir7%>v87gwhpC1nR(z0GHteFc5_^p+KkL-dgvmgC%U1g zH6;H50F1?67nNq>2Im_TVAJtAEho;!bp$uJC)7jb`pzDdq%bZA=?L5wEY=$!8zW zA#DfMz7nPZ-L;c`&GokbPW}VvZKN2JeuFGpTV&t(qX}j5p;RWSLqTK60;s|Sj@1mP z^y7ljgXil)=FoP$D4}hi)r}DWpqL<*zpDKc<8*0Yzj8uu!fVp!`7u9yoIZ_A z{)U|Os!uuCZ zl;s4hCAq=p%-e~srKi;*4x|bAs^WxItTXGAJYpZ02dj*R)b0r4E7Mf%h)c(cd$gBO z-lq3~$@Ct$U-XbpT-ZaGtIKjGE5?~!X0jmIFdw~QYS~;#K(8EmjWu4lq%WYxUPF&A zmWsL;s9s9hBQ+fw6*{&_V>Pn^EBgyNgO}qojkP?@juv|~1c`U|=fL0iH(|bgNnyEA z5XNQd1kVue_xn{PJ1V_&0cSEdF#JdtJsr)GQA2Tq7khl}G2oaHg_RT|lO%+LD^@$N zIR%#zu-ke8-Zx-f*n22jEGNE!7BeSoXn5u|bP*^BqDtB1sV|w`6BDc3JvgrXkLUm_ z`5ivZ%Z?Mb>^w|N0Em)h;>6>I!Qx+%r!c`rqos2t3)Bc%#w84=Wh#t}#LxRU)W59LNGJuM1jXI)# zZd8@`v@|aj{p?4dblsqjk@6r)B(YgEA({0iMn)7f2C#;NRfYVDy3%fX@1_|F-yUI< zF0UaQ7Zb)51+R;tQP{u^H#Rq#QRNWAXFN~j**8B3c!RAIInYhdG- z>f$xY%~VSgr?0S0sz{lz7dX}MLi3hrxs}1pn3Wg*yR1-RmOB4bGVfwj^~!668YjPG zh3p&SO_IEwP&Tu)Joj0|J^43Er8R~L`x*J^IB(S*x?tRjOUUFl6F&#jK%5#V!fq15 zRVlu6x-J_!>*=yQJ?Tb|M_(_v9UWNeP68S&?TU2vtf?o^YFur{OvOZ zK4INeiI;)^Z)=F~QRtF6r1Rs$yfF3V(nmoz)_ea7qXMezQy^JqQhV&Th_D!Kea05E z#02LW+8jGCmb^4rAqHP3O?`_%9WFjqzb=?KOAHL#m(O|M`=PK|+bhgWWm-UVaYuzR zxe{EX70)2wo5s&-nMrl1P~y!7KO|ti#EAHAGr9zFbrsT6*AUW>5&hA61ipu=fKSxP z{k7+kWC+o`t^cB8&l>9JggdH#tyC%qv~B98SyP8g-flZMdR$dlP-O9bmFYT&*vmq} z8$%8e#w`D)UXa}Mqw{K@=lC8`oHO^IL^bUXA-QIvm_mIv)O2?fXPm*P$6Q`Rp(K@L(KD+u6yCpU|CE^Lq#HdpKtYJaT;3 zkZbfqVMPqbE!AarmFgY$Rz{b(=pR)7oQ>!@lK`nB>qu!-iaYj=cr;3`UETH2RYeM> zi(i|)s{sHwY><(VC~cnzt^wLGl@A*1z}oH8Z7|An3redx@ahCY88u(O=`J$V$>TMR zlKzKNl#EY3PV*n2FsxBaf!4_eyKf<@*_5!!pW?WA#?*yOxY^fgzJ4Nxn0?6 zeEbtT$rCp{mUDgVb9H|l6K#@uR%_YNTjTuPR9f2D@fv8o&A}M73P;#D_tOC0;z}@noylvv1Mscd{k(fY9 zr~%i*P8}fuw2rS)f7|wYM~r&#mQ?fPJ6ot;?g;IxT;-8055MK4MwnWkFcw0a?Oj+C zk#=eWZ8U;E1SjIuIHBoStdCrnf&Sji3NxNGcQTHK{T>Ve>}1x1#DIC zIG8=#2*Qs-uTtpxp5;j0>0@M{boK?gU#6q~XSg#U*6};<8%$e^HH=gTOd77wjtd$k z!FnX%7KJrG7G4-Yc@jP%e1S#bu)@kslza}VR}R6upNt`>YbSEz(qZL9XJZBWj9vzA zR*PDMYB!?Vmg5+bE(JR$kw21}8^p8X_3*t8oA@ei7T)pCEjqOp_+7O380QHVZ=Q%@ zn%(O``D+B~@pyUNA?T_^fEw?m2T33^oG+5ZRMAp*S|LHLb-M$o;b%VyoKCKiA>c!MmHA4 zK=BI^)8sLvm73XU&JC0PW=BhvlLG7qsarA&pvOklluh_umG$vtLW%shuUm+plM2_0SVJ(J2~p$hmG9D{Jq}qAu}z zG97r3tHVN+DOO185Cp8MZ(9#t&SN?G%O|bw_-Gu0-d*BE%@?MR5rxgn%*^ZM z&=T||r?%(gg9?QcvL#2Ov(3++g_acElp_%M2yi7hiv9ML(E(k3 z&%=A;%JNp?B#`%=kYxxQH=68KnSSSX8uqHl-78UGddH=g`?!OmrGXa^JO8{Xbi-}n zRL*Nc=NP#$KK8{$p+D^&kRI_nMgPkS-o(Xk;7Q;3PY?3)v$$pKkEONhEpl~K&Qkia zq{-%5pU;F-urS2-Dp;qUSS6Qrx*ZF0jKjH?HeUaQuyLnYrR#@al+H_83H^3EPCR)V zqlzY(KrKb(R9_|~4+@A0UGogN`5gvh%sBS%SH~SIFVLg?@OpsInY0zdPrpnK^le2Q)YzLtSTmynNXw8*7S8R~th>f<1rGCQa>8k);u{IE&Afy)7Hr~^%0 zJ*kGgqmoQaDKsI?EV*-1M>sS8LtgVzguJ&F@6e@}a_cX39I4H#(2hlt4{_fcZ3S;~ z22>g*`MHKs)buw%P<4B8Wz&V5#CIse8(Y`ee2@go%`h*N6iurPiTfB(>Rxl$m3i_u z!?*j?q_aNy>t`^dQ%dMaE#gO;-$Qr)9&gQ@Bo%=k)tXVR!r^}HD(xme<#I%T1}>)u zgbZCH-NA?MSLguk*Kid2;qXI3cz+%)L_LFukkRjlzJ|S&Y{=*VQ`P2lW)0`ra5Ubp zcJYSJC6&N{2ZJ1#UvtA@;XgbaKe!LHtD3kDaI+wj7|>*vV(HBu3dB-U-a65i7&{#6 z=wU25%PBKpnSH%eqG(3X^3X-7X`1ubE>n8>BRz*Nq46erdjxwkt9@G<6Q9a@fq3c^ zaZrBhvr3dJ8G{kPi?&_D;USPyntVfUA>E&T;s^o^msCOr(0T1W6BWOm#0Lwg`yGI&N z2Op(EP)n2O=}9JS4ys4sCXdvFGHh`q#;0@M8vFc!QC0YGIZ12UKr!Yz4j%c*t?bWE zu{myFhSt9Enn2H*AkoQcp@uYiz0`~O(5C9zj{g93_NmNP5tm&Th)AK{C?`&f@5@@t zP;$fuCQ_*|h>8~S^OZh(s7u*TUEkV*+O~;sjTnP>ZrV?uUtLQaCP}?ktsqK8*DbZA zvWIRwlwdAUbk{)UUtEkVCM)Wkag&yI;Olk_}^*RCC&-xwqQeu#ha z%r7;#glU=?I9~B-e3J*ki2x;M6iXL#m%9}9=FZTBm9sh(PYGKydgeQk!HZPg$&sA~ zi4X5OoiH~;j`l~t8!ufHA>~Aan@Q}l1(NV!0s#RW3OJf>5z7lH4>LS9UJX%yQ#d-+ zVN!+CK3;BBS9A`~To#A~K|X3B`jJn#(iqc3Xoa9p7*LDBb^t`)o9|K$aI5JMA+Gbx0AwTpv)!K6m(5Yt1K+Q=4U&}F1 zIr{#yiW5lrjR~^S?8Y#|)D6& z={#GxK_NT-HFg!(3=M>S2>n$ z98FMa*}^u^u<|hyZmaPMrwGm$sJ-z^P`HON=#AmG68^f&_s>VwA}kG6EzhN(dlPCoM4$^qx6VH4J__sYI6C~H$D;SnB%U)9;!ukSHVfSVvgI3`x zHANP!p&dsb|A9{Kz0=mi%uz}#5t02GZ+T~kc9YIow8hfJiD0a=X_g}@PVyR!Py`|@dS`>3J8_Xw62Eg z%Dt1{ZRcgJq@^SOVCYY+c9MTE3^f+bUjVz3r;#P9lu9?;2H{>l!cYzs88s9sri=&q zavq#!==$>HNS8Kx0Lma5GYB@J?UJB~>+uH~vl1ned;di!!K-aaKO}3KjF<(43dmq5 z=H~?#^Ry=U{_}lBw&yvKn^kh|I9Z#cLcW~r$>lt$8aLb{_}5Ui>;po=f751EDh5@^ zp{bTy9$=`NEFM1^m~vTLqBXAF!u-TP@Vg1l0vp{6Ky3h=Yra2!ClYU`Cfzkus2Zd{ zo@0p=6G($pdDj$)BW8=_gcXp_)WTq5Zs#VarFMMkGm~cGW#1?mF^WLf6 zmnZy6mDLGu>sw|+u8*T}hK;StYW$Cq@j4twer8=3qhumS@;B_EhVS8{!YBO4Cl;@; zlJVUvVzR)#g)uS>s}>zXYPVTFV6jv~E`!&Gc8_z!Pw>^V=G!W>=ZxDNAIb8D96Q~^ zOKp&Un)}}|c%u4$0IfH+n3hc4xr^Yp6y*4>$QDE64^!4&W3Pkv?v`CxW0(5C*k6JBJUdI=>4s9w}Pm=Z+&qVc{@au)#OpZSy zXDOA}YCsd((UyA5S9nH@LjEIHq@dMzFh9|$KxwbGn7`28DrJfsshMnmkc-9;nnls1 zXEW&7e|f?~(aME`Q$JIZc>Z1-{c-g)cQvFLo$=LEN`!XF%=#RtoU0?BQuPHvLIh_7 zfes7D(VSzyJ8o7(mvuFc0NRSg8wH$3{qtr{S`f*a_7Y=R0uOdh!dy3{zq&@cenV7H zT76!LEJ?hxM+BGVo{m9|@bkGgLo;)?xrU($uNraE_nYEVlNoTnllPW4^;R443{xL)te~Yp!wLgA*!{n zLR1Bz_4~A^@5JI?5agZAqG+EyOmSY>?+QC>_$s~}#yI*`R*09nuVmJ8R2h699IIdl zfPtYSq!GbF5=LLEdUfK)k+cwbrDW^?9m8Gbsl1b}Om6sn#2{9 z%WKe^r!~na^1#6(Cv8oV(iKoxq{G_uAx-i*0=c0%T8@6|XhcY;H^ymg6p(To7##lx zFrFjE5|$JH)d+f-pfy7fbpGDc@JvuZtd}te-LqpBXrUGNQI6{HPe!QVXe{u?a8)9^ zMyErebV2{+8!X@fr@k}Pg=?{18Cs!E{libZVup6hR4?B%ko{Tfh1M!Q)48Gh>8zq< z@4IC-??M2BoO@u*OPXD;YcKGpjOHic=%G z?*?tLA1BDhV_mqfSkQ_UkjF6;lNly^buybg{{vt7JCjMYN&^ZV*6vs{vV z%j`8vU<5nb&hmiCp>Ma4t^1N0;;jqil2oOy-mSPL@dfnk_2fuQ@zC3wko;~(ia%Wh8< zuu>lxZ+4F8AIdx%kn?DKgbVS}Z^nQ(+%ji&E}G*bSwkQOX3^67dO|UQAqb9T4r!fi z&{hT)9-OMLZNngghEaT9Pi8DABuUetN`IHURY2l;05i%m1Kt3^Gw>wg`$;_WIs3j<78EmhXUWPPP+;{wB2jWk1F!Zprw&> znGpi&byOO78-`?^pn9!%YdW^kZ*ddH$s8#|a}(RpJ)B(P7I93^PE;@!QgaBfk;@re z+i#(jQZjQwQuGUrHDE7)cYq$lj;;vBW=qt`0!vlT}6F=TvGyb}6>RWnD#n*bjIWbahixO3PbnmcfbeG>EX72;X zTE#ZE35YRM&I1KRa_C)}ofRbtW=AxPN)xkwaAe>k#5ryQ>qR4ApM1?5mOU{3em5no|#nKbf%M5 zA{?SA6MTV>v|L)MS5y{m^-JR6-EtbX!c^Pw z+!}+ViNmEsa63z%Ykc;aFfPmucecd=mwszpNT8ZqLIBkvFWX(Vw%&&W+T zORoy)lq%s=$Cn1+3E-SH)YlJPZogC)%k4>eAq1N%TiYCsi}CUnQ65r6rV}w}OgLNl zc&nMgx_(t&G@&Fxu>cFrYLaNb8V;&!D=xb9rE6Ba9rZ#4*U5RQ+`!Vtk2g#)30rLD zd=i#P`q76BE6e#-g{pi{7Jj@z64=SPSkpzI8{NpY{DRH8%3sR2zd`iGAhMA&bm-m} zX&QQ;7a!L%ieFJ~`;%xQjbmxTTUb-$Ds7E;=qeX#qZV$^_|QUdBxiz@lMfN)mx4X_gRrl5l5?usYJ^ znOuGD@S+1X6nx*$Ju+goxskc;O0`q~&3pLN2>5DjfKNeMH5soIiV@6dApJLvNl2yRzwM8T?wA!1}}0PRmGAhp+Yud|+M< zMPbgXEw9#HL+$gF!U+e8R2$wN3L|i4Jw2TLzN-q=6POPoLkj9JNm{BLh~5>x8y>;5 zK)S%HYcE4CvOKFPu>iB`OhUW@m^&z|djCq7lVmW#(nhe}zW!XM6Z>A4RDBHZdGf;M z(tB}uRfpF<=qZR6)e+<~?aR zRG2kpv2aqK&j5-$PH)NE+mHRK^&aSSiiu~GHBL-nlrdv}=^`-FO!tnA3Lb;ELx%6z zznRIg_>Zq=vF&Cij!d{7KuI-+RpBkyY0V<|k3YuNG|AcHY_!sR#s9FEOH&)h&de;a ztR+}u`!I%!$P_sFQ=$|dnM*7`m-Eeit>D{c;@FefB<&9k)$s3`2+!PW(#K$kjkWDpcKnVe6Yo?dY?Iq{ zdQD^4jT@0a&NxQ7rg!@s5g~H{ngEf5Rv8U0RI9WrUdDrq9gHOa#UMvson?0-lqYso{S$6V?0ijAB>xZX%@3PhV zyS7-${%!ih3)0-DC3TZ=TDc11XXC&Dfs&VKNWG4;!purBeBDX_Y)|Y^1GJ*<_!dtG zQt>qun)P0xHT>snF;ubi#ie10CAC&X+EhzVZL-SCN(w! z5E)GjE<>373VcNNhaVK{vK;sJHBD4p;j*CAed*sc5fJwtV=8~cAr{J(UH`9>J`Ue? zckyaBUg{-qW=tk_)tB{Okf@aIxGu(Ju$q0Cx`GDAhkz4dVN)&F;JuxcP?f_DspbC6 zh?gjrDEZ|M9#1}of1Z1J@Lg?;b~x`+uj?s|y4ejQ`*VP)rXlI&x+>C$J}9mwtR5!2 z+-#^iE4e5^3I4DG?^JVD9XNR7x!$bD0H;fN(m=T^y~|;{4KMR- zgxxg-qJxGT)dB z6C&<39FLKy#AMBiRs-3p+q?k>vUgIZ`sJG8lnAW0RQ$!f3!?sJpM@o;@G@>-@W{hI zL0sB|eZ#v9S~rc5wJGn;tyd0|WDg&S|mB73GA3 zAhc7^tO9v`%w!-bKNQjE7O{A|n{@TQm4z(s5=EyR8-4Yyp_U(y-gLrkOmaoy-9nmz z80Lk__-bKYALme#pH79G37yxcS-GPvFOd)0e_Q%TpG>Uud08cloEn15s7k}D)1ZvU z=iz4Ei@qBLFpZbz6GQuE(1V0+ch`HRXDpH$jbLI7^C114J3#Q(WU=hh(nFinVAmb> zJF%|#UN?6)e#T_`LBYr-8wM3#q1Fd;{a$RHeutG4$8Q~K<3IPavqub@FbNwwbi-3D z6enY1q0?s5g>pBh#!G*j{2qzLw(IqmmqOFiBTel-`6d-S6|gtASxsf{;` zQdAzsi;LrZOt(0JazNz*Y6T|7KSdeD;Qpk{p}X{ zIiiu;)QLepLQg-oH@9(xWLjps)(zo_8j)JY+Q10oOAa%1oG8?0J0zO zQhiw^^D6X_*;lCqp^wJ*FhoM+K5_0CV;yaxzftSl*K%47mUmOk+=dc?Z2?v7|LBgf zdU6sWsi(@1qlw|;*G=mXg!hapWexHpTu@LI@e_iW@>Qm*ch-%4n=q(8oK`k?XLc$Euj!I1MbK-tr}ezwv>Bgk=SGK$ll(i6Ai`u3*n0DZ{_<71NfUrQSsyhE)O8 zam%y=dnEC)@-oLDV?>+D*1W7+rhnF+~LB^k|ODd02_fVj+t^MPn>$(LOZ6slfS@g;vMJxwX zZqvBMk0hKt>tfZw0<}8y-_G5G6G?)nwss6*Y-ygH&)A=dJyC~1)XL*=efw4VIu-%HTBFybqf2b673!!~qF^{?i+`@ZyHc72InR>kV_z-o z*}P_07om|Vp!;Z`zMLo-#rs^cTZ+vU;u6zeZJFYGxnChxapfVTxy>ZZ%r7<&B^W_O zQT$DDk)qmBCPWS0C1hhWb|l3fGOJOzk>b_wHp)d<5<$R_QWPB`2TdQ1#f z{f($CA!vdlaA%PYTOqXAK|kIqmKY>YOwScCZ$CxRH^RK5?R!3%uT+UMRv(A_<9vKO zGj)0o2dO$3bnyS^Wj!I~_{E+teT_7&ZZFj4R_3IvzrTNT6D3l{-g`5tTSTvP0a23D zQ6XUW8YQkveX&+;%KDl&HqKWjj+-Y**nZN%>u$5kX2x+j#UEYabfV=%nBgfT$2j8T zfB~{b!%U{^vKN}x|0+||;#~VyX^FPCr`WcU4(#Yf&JwtI3Q>eg3ZMFyFX)Oo+Z*Gbn+f0rRGORfV!rx5f#5?_i zc5^w6Vl?9zQSgZ`<|V%@LJ6=tekb)VzD*b=@l)mk=4$3=zlL3{L=gWqGDz0c#9vDv ztu|!Fj)mn&tq}XB-Ek5qxrEJJ!`e~;it#A!hJ$7RoR_iN5;P1~`np?uJm`pFJ#Zl~ zm|o%(6N-U=OOhO+%sSo0yNP+&-4B%;6Y-UjPH#4B2SxX|)1hPOFv%*BOqn4;Iqbit zQY$unf+&GqynN$98?V_UclR`7Y#|V#q%aPK>w1Lzoo}72TB{un7kOsbUx(lWCNhYy za~KN-tUsPOzvPb6?r*MkT_1*y&#hXs_Hi)8;%ohE5=57eJqwM6$GGy+WMq(E5Aj7M z)CfXSE-^h$4$Kj=>qF$Xhy^2Y>>y;wy&A)*o7>RXL$hKT21&6YmTLGk_Bats5pxrF zfKM~=Moxt4JIBFC|B9@KSHwt0eKiMf?DeRi($N8j%=a}9jx}nUx85&6lDP+tf=NG# z$1){w$SRn(xf*r;A4}Te|5l!sBG(r3Z8&O{qFuADf1+(J3)M_eq|8-xNogp%VjeZS zy-g%}iO|v!BqMF!GLM&sb*bi4gGDCvF>!+JFCYu|W>us><2X76yP@mB zaG4=FT)xWK@JX6pkS$kCH9#20`$ES31E}QDD^3F994vsARXfW_%6i${$4@-XnkDy7 zrIS*{0}0SHQs3BitLGS3K*ofyqxE>$`4nW zWO`z-3lL+adNBlZ^)>4NH$^mY`s&2AdI1mOTCbE4HZF#oKZ)EHBr@I7i=tZT0##cX zfNdb*TpBa8{H~+)B8^y#QN`Io6J$*W&cHH=j0Ue88Q+-Yth8R|?!2bjN{ia@Q3g+Y zm3`Nyd4d>zMN( z|CDI_-gL{=TK)`AmNUn0o?ECxMZ2Ve6!9zzKqu6m$>YrWW02n^#gt3?qg0vJbMt=y zinmI2CdA=LnA1;7E15>mP3iPrbtm3g9#!~Dg>A>PF{3hr$U~5wFfdwA@#c4 zSZcXgDrt7fBY{%m?}cd3XE7uBw&ZH_&gBhBq)|&KkXidu1G8nwN@`aOq{HY1qE+>a zFbb9#JUyn6oDOM8tof@jY~NZ)Ewboi=CIQVJY9YC^`c+hFt^cpZZVle_2@Ne1_YpCU7+C}asgGnECOu3V?HQWg6E?L~-)l(WJ z8dP14ia?R7Z=fBIM2l57y2v5qx@`|innCY{iv|K12MrjBK=Ex{ zCKDBAZ(Ss?($Zdted73;H_4(9cvf)CU5!NJr|?lRArm^fEJ=cqqJ>9f;@45DDzVQo z1vVL$%2-n0qa=`$UuD)}`kncy;ANghAYurXbX)-Ra>VyZCE!da-}nz;=6F1<5wKX0 zF#^MGU+ico_09hpg0l0a0nO65KL5L`#9&9>SN-_`*E(6@pP~3}{MLb}t&Er3mnNAr z15>ivrbggaof`l;<<|$dYV+<#<{ZX?*um}9Xeu2Z2SW?4;7N@6uID9MtO*s#op{L_ zhUsG8HM(Dqsx&yyMQ*Isv{wsQ`7&!OVOKOf3II0j(u)d|DZ> zw7Hcbe;=^IRDEj}?PoTT>ZxJd{D0veuOn8zaw$$e8HzEPe7M-03vi}D#FV2c^1Ws>WSvO)D)LA(V~}Bgb3kUdbBdeqstoTYhK$WQ;m@ae zJ<88--~%_mLc@<}BK)R4Imz}`gM0t?7lkBw5@~sY3U3*ah7G`;==Ny6nr8ydTrg1= znE%AX*#x_cor=hjREWxSUb8u7J9x*a{QIOrfi@|KHiR6h-(bFMXO!Ok$6;` zVyHG!M~GH>)sY{=65m#U=ed@7(ws^}AhMGCQcZ%ol`7JOE~N`>*`7Z{E_}Pa=&ai6 zr~q$^nw3CTe<#f=9Z&JS8nf*C!F<}Cr!gZ;j@KQwnb))#A86b_nJo@86A0-euo}jj zM@a#Er%UwGX}thIC{Ok0S^TjeX$p@ATYi$%&R671#uO5w#8LWZSOGy8Xq#2oW~?vxreSU=fz&OXCmkdU`F1hM>4SHeav?ZfpN~DuCE3XL6;}7 z+FeceNHQOPU|?VybB?E%u?N=#;!qwv4~FjH-6d%~r9RJ!JWpPB8@bCHB{xOT322bf z1a0v~lx3re2jX2S${UqQqy~409jl#UbaJ zLL?6N%LgX@C6|C3;W<;U3n@JoIb5q7Gh$r!auY(a@H+{e`~ah(h~cW8;qXA$w7DsugqG0?w+>Tj)jvChH#?<`qq;k<>mOAnj_+A#@fS+#gN&WQ)uoI^#H{h4%o?=Qt~9ysQjBolJX<;m1sf2>ka$jpANa zJ-{q>kWbv3hed}TAtR9O?nWd2QKM~EFGiOV^$|71*J#NrpLkDN zGIUfheLME)Oi+&6#xdyFC|`I_nmc~GMlH0HCf(>K?-OelZsxdtWY~!if^pE$4V=sq zb%Q23Mp46C<&RsC4)UUs{~KU&qXp{7)Ez&Gd?vj{M7Si5WQl!XD-qD0ugUnm+jsQd zTR86h&2H%cPUS5?xNl}t%kzC*KI=pMQS%SGW7?AshM_v2PE-@BZWoS}rC(%@NN18V z@OMzA4F=8=@IsgBO}vT>X0rZq)d`dP$O-W5lN}%vO_`o?1zoX$#YkpGB2;+#rj^!V z3eSzieB`3kVTWF3z~lk=y%851zQ}y9{R~iKq4}L5dXj+@%@TFvY(@qtxkW zLYLmU@2n(*s6w>8+123c3UkWOyV35{PJicAOM@7^w<_{XY(>!xOT;jjv|>c7Ak=un z>>f?gOKB-yACX!ho8LMXFn1-;Fk*FeC%Y;{SZK=fcgDu#iPuaNto=}YyvbNJSxEWq zyH6x&m~jnyn&M0-weeb3Csq2hF4wOyr1xWpC-X9q_=~>m{t&%vJS!Tpe2x%J<96^m zXz{D)h5wYy_T&K~XYG!w55rvmv?5A)8dguk|Gw4TK_(er<~#DYOcMPe+u3?k$2cY87#K+4lZm;_Rjzx9kVO$v*8U2SwUirb|B=6|d>C;UNV=8g zKfun)2D=ca`kuC+DvcI{6=30KIx1y&u2G}xhY6^;uwL6GCK%HNW7p^WY^{HBwW14e zC*2E-rDUgn9Ee(k`y!KW>+jQ3TH*j@+sU(IkXHkL<{Z?5=HMDK)~)<3*t?NFtjoeB z=O>fCLixG(raMgFd2de}_-cPLxRZeuImCJhc*M%}*xl4QOUY`74vSvpjED!TX-uaM zszl9-h>o6DS)&gM63#6Yc|(vj!+079c34}fQnxN&;kY$$IFi3=UCzS~(W|S^etyk^ zR=R`jy6>KB4U6QNPKm{RZ@mNP-pxkt-F7&Rm!e+6>cxZz0g05-_q27F=b&ktg4*F+ z=Zc<*n6stQXqopEWt0}xjm3LR*$HKSrzQbm;kd-=Niz96!}o`*)hvWOsq!+kOrUim z9b94%T^2wl=YwmR?}DMDN$xx116vcvPxwqau5NN|BxjYrOC@^4ICt%|2E;GCZ5SS4 zu{n9P$yZ@K3KJs+2NdJmLYy%{PKHO`Cc$#T$%xc?A!>V&fU>hJ#4vJa8%4}H$VV1f|baW4&--x5`YpE3`tvp6HX}9}wn!Jn@ z7w7WibZdHAm^X!17NnDMJlBa!or{JCs+UN}!XTOelmv;cohVz+WTkh;eD~sp2*J7!BEgQ%s`c1=;fZ~#r z!_3dU5|i@>#gE!{9I-Q2c(d1M^P$#cO}X#&M9EOQm4@QSnxu!LS){ZCcq| zwUcNTvwPf(%ma3c;XH&>!(uNeBfsU9Qdo!RCqD<%~{nC-KUS``ecjD zNvqrnJ@V4mbzQCoqSvK|B$%k^n2L3xJ3RbI|A+7%=5-A%wqvsuY;;7st zH_!{rb$*+b=701f`K!>N-i5!~58Rf(VBOkqa~0V&D-~hgh1eok=Za8D`5kO+AMgf3q~*XQPvdoWNPsUUauXM! zU!>(6Sh;-cr`mRJRRif6?M=55O;&qO96l!D&Rggc?qaLm?- zZd-C!SAF5Fya;3ZmQJM9u!+Zp*bAEywOgjk(n{{le>D(hOIdy5 zbBtRwGzx_beOqjemb3I2dTaSK;3yaI$-|tsTf?q43M(XP>l*z=iTXwpVYo;Ab`@8~ z$JP6^1DFeV)K|2VV433Os&^yY{GP7a1~?WR?Q$%Fcg-#_l{V8h@0)l;5@jI)w1_YF z1FDtTqKERxTx3wGvqD94kDN_j?v^09jpBB4ijyNGf}j?FTRS>+e<`?ttCaumPLLZe zj1)2xw{frQBKecRSVjFmK=h6A<6LBCR*3G~@yfd9O`9XPC|Yq+5LKqvxBmdRd72Cr84)m~&*BA0%~D(DRiBMzD!Jc-EiO8aI7gepTIO zyxs8d*U&CEy`@P=%SIKE8=Gn+Hlr?)&JAOBD$0We)38&ANP^t3#0Lv=vSA?IYL0Ae%+W#0HYm?92g%vtFB0);+2}= zP*W(#wvM4d-mJ@n)xKZ#TW!>L=c64P<`XMWscBL|vUgnM3D%|LYffAlBxHBgWoR%} z-hs6{M{4v4drdOoTM2z%pc&=6{(mf?hj)Y8>k((wg@npRjm+^> zEV@)mm!TqFy_kGV{5S_eG_wZGYb&5e(e1Ix*h?j%r0`6~q9xEc&8oTS(tF~@9 zo~5=(-Gz~TxNMSF#jlB%$|h@&)!?j8D=m?vmM7C+Q$^k|1Cqfo>&fJ;yB;6bu2Xw)_~zQeee zY+bJU3%#Q1;W25J>zWqcL~iV~UKhPmf8Xl8F~(2e4ND^D<*6Szhf%tcuFQepuj-Gc zBZ_0L@1b6?nEqOzKZP|~`DR3PnR`|>S;1p^!*(42tVFDb5s}vGH7&9@#~n1I4#{LU z3_6o8^IRDKD*t3uMk^8=b%UTUL8`+4Kwiz!bD70KRp`)4L$R;Cnw2;r%Mr#S36k~K z?z2H~Wml|C>4~yZEl87mk_I=G!8D4=HV!sBN`fTDE9ugC*u)3}<$DxQyV$NTF*2Sb ze`Y-|&fUByzR&}vuv`&pPX6%RmqQYlQk`KbyZO;6do4&yb#c+()$@$W2IQd@$Q!taZ-V0R(3Y%io!?NA3cL2Hl1Se;Xu%pMIlmxGa<7Zy%=;!qMG(4<% zko(IYwpZRkVr>sX&3=Mo`9kqM4L;=u+JL|DFcA0)n@PM^svB*}=V)#CN+52ZQ`d*Y z$uvF`2oAF+v;Rd7Yi~``zu!Qx$`*x8TBFEa%G9K!27|3+ve<3avj2fH3obeX5VW4` zCd63c^BB>+CdX9w*OTZ(Y3W7sl~o?>HH3u>6+}@S%PdPLH_;~Mqd)oSL>JFh%S>F# ze{mxuEE!0_qGX2QuF|Y{iLV6`O}};Gls9}zq^K_Ml9}7S$c{#g_VT5SKlzJeH4}^t zM+xqsGjZgV_4!$cp311Q^Jb?Yl5daeDKA!y;SYct*Gm^fV@fL7=qx!=KAW@bv4eH3 zW7U5iDSq^uzy(Mm%J0_KV$tU5>I$;s;}P5lYi2^+nT?31g3`>S_@YrkP@9ikm9@m` zxD(R*B?3AiiVq>a+D|cj7bu&Oa!v zkkdv*Qh?qWSV*sib7!~mi&HY;3prXypDWww0;eqA*m++RB`!JPR!1B0YAm z$s}TNx|u~O0dhkE4n0Qu<*p5yS>Ir@Q%dUkSK;U~UUWDLI3;exOX(TrhPR-g(!`3^#?73A744w)T!u#igOdab!hy$$o=U<`xf}gF$pS#Zaiq>Sp{mgly4V#$TKYQ6s{ByCn|C@`EeZM;F1|;C z9N*~=cGU?25d^j{-mF%4ybVg5Hr2$$75vu?M3nM~pCn6`dz^IeAg&qLQcXLZ1hn*U zx(fEH92MCFbc9h8o%eSsu7`40SHi8rv4MEv2WCkqM566H7%eoY&Bi(lX)5{^H9NpU zt_kV@IKO|bF2E#2fOJJOf9%5@JRVU!?}W6sd9%E&^#{NMhZ{zp)YJ4BqFQ@cGlyU( zp9MU{EAv1LI@}1+FS~U@Cd8mWpGHk?*-S?Zg>eLDHp&F-4^RKYXhj99BeDMlqVh6(ZQ(TsRhonHBT{knZv#Tc|z|)pkDPxU)qo8OU#~5pXE|w~_*8T*7po zakm%fAcg6YnpG`)dIM$ZvUWnw1Kb(BYdi1bL4o!%!fz0mBtSx~i5NmY+pzMmfs1{D zF*+2E_`a!v6B;)X>t6#=XY(&&my&zdm=P?P1e{Uo$nERz z(tTN(l;yLw@qHF%Yky=ss1di@hA2&ti89IA>o9-uRrNO78~D2NOctrfOS+7}JRZu3 zQjs^XsqNI^uR~hH1KS6m!b1AxQ@aNZo%FVYG%Ordvw++6=wwL9q+skK-v1V#J z5u+xx*sDGPM}AisZ|XMg=L6QxrmpjaBCz&O{S937JlY~MS4XJsE5B4 zGdY{$`0EhekxaG{Nh71vn@AtMvDzh#CUFOg zX{uTA8WVl(7U7y$M4(BOO8m!HTn>pC%3KXJhWdJww=5PswLEN2`Bnl-xkOyAKoFBA zj5(KFfych=S>8eb9OQ#_nKJaN=)Kjzqtr^t2@KDe(0J6~3b((@R>v+|&ySvgqQ-_j zJR`?{0QzH-nxZ24e%UeT)scdy6U_XToPGFQfuIPb0?JfGwX?pGl*~QEtHqwy?CGMT zb#dEh5tY%f=4ey~leZ?%oLEpl7cd3+`z^-kZA(cS6}2}K=7sg2S!ZUZBPSZAsTKRi zx~SYY^xXrzTU+7Pg*UT9*Zi`Ak^h)Cp(Wyutp*8kF=zrNR{QFSZ~ai-D(SEJoZ3Gn zgUaGO2!a%(vI!2zl& zK_i^Rgg+|+IbbN?NqKaGF;M=tBxlEXuq)(Opsj^`F7)I}^gN`5-tS{+m$WPL_EKXE z;$7$`GS+|03ylQ0rPyVEbUqpZdj7RMjgy45VIht(-)a>AFU#A!-og;MdufsK+BpR zWZbzS$Qo;OB?=psNt?n~b?!I>va)@|WO+AO(=yla5O1*jh)x(_Q_iPvGnCLUcd?SE zaLuKVMDJk#VPka7K!xegD!5@;fr7WsZ&ZHQ}+YAA>jy01$2 zqw$Zr!78zR*`<+kz_)l&a`z1j=q{yCBBd*EM*!i|t#Pgza^a*uQyPv|gg((G){XNI zaTS^y4hS>AtMC*NjREl%{zNv1R;#my?=& zpjA;4%1Gq7M^X5v!em9gOoz~9F$J?rCj$;lW=LaSP$P{{{fr@ z5dZv~nN2HH^+IJ}-f2YUpG6amG`skEhPYg_+U2uPhXe7kY^dz);0Fm~0nFnHhGV-Dt5Fup9VsNXTFa55T_%2H#T&y` zUEN&xtMjW26mowI5Zyd0D?b~P*5KVNwuD5RQ6T(CX42T=GPx2Y@|?$NG<#zj51dQ^_kDT+~On zJp)%wl2tQoITil{_HrA*EhmffArk}mIltEcvHjrt4}c&81*e=OfcqPn#{wKdln^Ny zg7RVn26{(2haN``d)Cj{9QV5lL58yY_%$JWvgd)7u%pd0msys15iD_`w%OGqx#>pAHrRm2`@bbWK=$3`r66es+GmnGQsK5 zKU<5Y4-kc~=jt-c|COTjPR^P63j$XIx%p0XYwkbQF;md`P`U}T*xp$$)3l#YHuH6CXCCB^9=OX(f0FUC)?&Zn$&Zf|`$bvdqF zQRXKY{{akBH|S%#cU!dC;w0yiMw5Bi~8R2D!gAZZjS89q2l;6!KLv%uytzRp4ca=tItT zrEfHT#!ad43`l4AhTeDfbb207|GR)X)_Q&W4Xx&@Wb!E!f9Vg#ZpBYW#K#HVyO%YF*S{bN@~zjL z{*iyiID2&LS!IKMxB0 zqr1nBZfw@3@8V+6WzRUJZl1o*SF!vl?7_7vq)U#PNC45g6HeHi^rVel=Mzhbckng!C zGX@!vB1SaEiCJLR3Vlfs_11!p_rwjOe0Pbg^42YTe0kw$+c)|bOlDQv`wU^(A8DC{ z%UJQ;9%u|77i3=EGk;%+sM3oD5mZ471Z@`AdG&U_Z2R);>*~T*2Mn)5@Zx=zzNE6- z#j8j=O)6+Zwq%NieGS%~eO`=Zmy16}5O9*cKP5N;8QOBFqYuCPx(-5|rTvVp6#6i{GXdxR=81|8Jt~cKi<2$%KR~?A$8TWQy5@MrzgC3!Cc4)C zj|7&tl@yugW$xdHEcNxjbDDG#-H5_q--GIDM}%TbGEOk%{sTk=7lOIFZaL?Vhbn3Z z+rpC9F)m`-L(6wQ@D;9$88VAwZa9RMIsh4cvexp=M%EuPrCIN2=tbvnElX6o$LRx| zzKHNu3VX#lP=L{mJ5lK4j=7nAeP)gO=Aoh~1FoD3(AoP$&Mr{=6-fLBjyjVsYSf-Z z=OhPdNu~WEoJ#XG-sA}T-TN&;Qk6EqwE#V>{@n3DuSU8m`@kboTfMq6=jF}C4+G95K2=@EKw~H4xTnPc+D2lyXdkdw9pbwub zDe}8df`cp7iDF#5HT$H}vSmL!&I+C%JwyqSCH%{>TAj-$$^6SIH6jd>{wkyFKD|q= zVlS5l34s@w4=;47F+czPZ6*i~A-Aftd0bh4&@dC3y_R&Q1$#zRmSJUq=wFy7n|_R) zmYF_8rqy$JThQGH?F6-YH76eWY^sy6aRPMl?%|0?W%#{RKp606w|Y-#Z6d?5RS+Z`c{nZQc#h7~PcgSGX-Z!NTN zNF1Un@b77H&N(Q510aCL#mm;*fp&in8QMnJ`Y~k>ugx_qeKz?2h3bEo};Ea9V;r4el{p#bS5xT#>_c0a{ZQ zXYU-(Z^pR#Zo3Mys;$v$nKXMX%3+T8>Kx|g(Ralj&lKJf)RXF51qBf!I6@}?Kynrx zC2IkL++9?~?-5iR7+uz8I??xGh*)Py4?PZcb@aKCRrc~Ty#D>KZX}s=4F)nlNxT^R zYoO^R(%Z7*ugItuD#G2X*&Sh7J_4PFG>&jncH@Pcs$iB22i@6^-ZxQqKG))nvejF3 z2fK3m8}8K%D6c9^iiz7d$5E_r-8Sxlk1*puz+`t?XH!w4xNxJt9;zQ!xv`GgR!!j< zxF%pck>O1}B2Dy1^*}-kaOq;Hk1zX;L-x`kd{fAH&YUOzrec_{wk%JF-4)dWU1-_@ zdg`mE8FYA1^2#TA#lWRlMM{P}xKQrmGM ztYjxv;>QNdW!O)`{bO`L9xIOndCl|s^zNOpuYCuYa-!BM)o}!;4wl9q-j#xArAx|K4sCbqrx2GkRX!+JorK*x^<^W*r;IvgON6?$< zA#$wX$=O5+%7qkp6s2$IPvOr+8s27!xb?N*i8DX$fr@mM1OgtaEmaC%J>Q(7L(pCF zs;|e+lem7DWq!o?v`*xF-dMh@UNF!$j>VBwhv+-Ncuml)z5ySDAE%H~G3TFd(NAUV zIw707dMq&%>8r~V)U~xf5D1DJ;9d0Kf`yWV92tjIDUw^umCXdTVElU+)7)Rf+c%Wx z_F>pdyG8Q)`43-5FTVpBn8EuB+GKx}by@YQ_7kI&6o$~IJddYlnud{Dlp=8WPWBb&1p2bsgZ;=_8Mj404n3^fR7;67p z3f&~oCD`$flZGPhqiQc{7-p!bX3nY|Ug&&+m6?nkb-swl*v&o>?c_&hmeVoG)EeNu zSZYsCz^|#x$C6p7>mOSc-O`rLUhz}Zx=rp2z>Y#Lqpy=#I5o6++kk>v*1?wk#M2F9 z^8*3pxiU(6*`y(6NVreKc1>zqque%=pr`%Jj~~0;O2ev@OxVRrw#EY1?e0H_JUu$s zV;R0z%7;YTgrd4p|Cuf|Ue{))k_UgT)kXR7+P>}TKy1q{omQ)wxI9^8#8VNgXc3YN z^~;`PI#GW25iF`hA!n2oCb^I8(TC7k;)?qA&6l1NBrU?U8$>v7U7Ye;aykV(;b%7S zf_9W|QisV!Wk^PAG;a7~s7sG%S%(I>NIJT`^un0*+SzBc;+ME|s`_e-MjGQZ6%=|N zQa}5uN__XO`3dS?%P_u{5$maN+E|&Jn583-j>M$Lo~`V;n;R}TB!$OQ>8-TZF5px5 zB<3OVw6*9{or|}lYe$9_b$hUx1>Gn`zo|0q1rLBdV?o_+vS#cC1JDG$TG)tiwG!1> z=UL+Ey!v>uuUx zbD}aT4^k6SY!@(4JAW6te`9y&jpVEb!IDSeBt)MHcbDH%Hr$x`A7BaKzxn^UuL*r| zJo4J=q7ir5<{a)I)awMxo5b3`@S>JoBl)FyP7E-Jf6Z?(g{<0(Dc7;m-AtQt-zSGlo}Jgrv455>B*fRRMwnr4PT3 z>`ZM_o?|{h@XK-um0S6}QzcSS!z$;0OD>X3fUp``(n1++!ngez-t+%v$x7OuDlJ-- z3`NvJzbHx?wxkH`jW5_;D$@U@&jt2W@yPG` zy~m1j#bMl&+1HGQw%EG9=I-EkfAPx3oKL8C*uf|`7NIhjL57(N?2)xg2-kbfS)%c; z(3)>i(30rX^wI+r-7yvlAKLF~RU8k7;DJ8w2=YW_r{x*UUuj8J-*aY?2dG%hCqQc% zK~#m6e?V;M`aEGrY7(s$0dzyrP&WQ{(mITN9!;-JM(nJxRB~ z9=7!(s9(cy`%V501Iq_%Z*miut+Z#bNVRi4=y5bU6U55LqG6%#^I{@S6>D+Dm@~k3gntqNNltZ6KFN#GcM+H1T15cpi1K5kd@U_Y#+)^b3U>Jr z@+*L)Wk)n7KYB0q*|XA_otu=1cpG;TaiWj*6noRPwI&nSnRdhtbzGZp_=U zG`=GQ+Ss0})QoySG1fu+VGlrfZNwBU+7|5aaqE4@o5I<4R>N zgjl(M2GNAP8Y69CJg^WQ#G)(y-;8-ho!J;GK*_iId-|_|>_qXryaegP5^*2W$2mgY zo&1(Rd^B}o7}YnITTp*Zme}}GUB(g4L>?*HO@E?IPlHn*h|n7{E{vPyXtdSBgubzHz>zR-^Hq&LU8R(=>gchO)3pgDZ*U zZ{4Lzd|m5t)0mC@D!tc)L!wxDpegm~Z>o89nY|sn=kq>)_lZQE+m7D@v*;8f z2xM5zi%jk>g9pM6Yw+aqDu-%q?bKq?m@lUMg(T!ietv=kXbP1QMPrV3)r;h8n8$DAtJkz)Jmw^sCj+t$KIZH0e`=;Z=uIMEHr77 z2z=$jr9+Cg7y@D>eqp;UPwTUk+mrDwPUB&pN@CkscZe|cVv$WmKNtGL*~&KbZMvu0 zE(t0?*CXuoQWNB=*cO3Zc+94Sq`{}P`#{B2Ht?HMXER!Iyt;g!_55ayeZZZL$*AiG?FYVJ;`J5J|QMQ+olT{;&# zSN5NsI(>|Jn_4C=#}Tw2zs3F_{>OE!?4SBLWcOev?4+aQh84Pl43xflomDji~XGKRz!N2 zY}HY?BMgqiD!+T1<3HRxt0ulvqMJ6Fi5O5chLw~5>Fes-&(aITkH@DGG9N!*TNr4} z;}ed|DgAUkC$8TqbnZ-_>Gn{7^!W0)aIEDEBF!^}ry{Pi-S$biN*pP{oC&h}?`&wS ztu^w!G7Wul{TpUzxA-(F4A>8hGdcS>`cB7=^z04nDBjsn&{fp<6aQK?lA24&8??B7 zvC$CqHsrZxp}&5Sb*OClWg9`BPQ&e8+=RmD0-_40vtoD6$pu?oQ$7mrqxXPrM$*4L`@a`c-pJ zLUclZnxDOGLh=oc4OHGK)Lhr_n2zMxcRBj@+NFg~=D?uM9EmF< z>p5!PFa+z)TOi#3e(!wlJoV?*g75n+U8_Xq#uEM;l9jm}Y<}!5a(+V6HcOu|hUfp> zS-tpv^N$WsGhA*TtuMfFsjrC(#T!VMfv_JaZgAp!r(s1gl#C*2WrvPk8*ecI8sADC?qttHBQ2CW`bJa9+Bu^sM^ZC0DVDMm!r+fP2{%JU72j>g^eDVB^fm7hS>v68 zZbqiF)A!Uc8AUpuwR)*y3tjw+kKqa#_cjfxbA zmS<-LNTxZ%W?G@JMeb|Tvls#mmZ9C}dfKBVTzhl$IFHNJv3xV`-AC5~D%jJY{#w4{ zmW$*-PnA(7Uh`Ftw5V>~+)S9yOPlbVe_t*8vKksL#EWKFHSw6!;qVz#EP;cC1LrXj z7Ow~Lcxob#AW9y+=88d-I@JT!H=dj8{W=ag$jK4LS_#x8Hr?cqQFU@ye3o&UhhT+h zwg^dMkW`Ago@?}?<&@RL%gtO%vujtEgyyktIozOciN~twm`LT~OCX}gh z;wdfUv6{5YXW8!xyVG}L0xjTI`#4j*H%_ZFG)fz~$(bpN3=s_e>?P&mBD^PIm~D4P z08LjY92U;~#mmYg0i?#GlgM#)`U?Cf1nuYGB_U}l=3pmOr5(@S%>h=$utgiz59=_0 z4Bf6Ozy61b_P~vW^lxZHi7KRa%!hIU-}y5WZQ3xbY|oPU9{L=LJiQEq53@<4HRylI zXSxY3-X=kI8qC7SPtii!^5t5=aJx_{UeaNF^ zRr5VENut4(`W;4hc5e%9%R=?L7*Xm(^3_4)TxUNtawTLgp}tg$0GnYWV9VD0Zz@uazvmNaSFp)(K~5Najwx=}I-a|}~4o3FmK(t5ow#uG!Gabwa(slzTf?a;wf zbT&eOAy>^QKMt%7s|J!O4z` zMB8W)F3AaD1*@!5nQ#4w^sFZ8!TXFTxjXH)g?&vDyKd$u$TKSZv=-Roj8h!M{XkXX z7kE=md6oN-k+1ig=kj0*i#*#C*-WFX=(l4VJbu;nr7rEgzQbVEqOc7PV^xpm^WX1b z!d{y<_Q;XmF~ilFHXoA0WL>Mg5=q{KmA0JvJK?#TMt^`ZDjYKoU9vD~Vg_s(?JqG; zCx5uaP-gKUZxbwTOn>_JCCH=9v@C|%6|I+XG2hXv!V7O0rilWm*%_5-Z%ha!A#%o& z=8sIL)`)FI9h=;F2PCVd5;&~U;~J^FAxy%6T=exoL}8&#N@Zy#T2~`_(@1)L4DLp(W_i9!$zD0sAcQMF+bRmIfqo@ z21IE}4ZS@z3+M@C2>3Q`sc-cZa-W-aW>Zt((VY6h3g z5|0sYV+8TxLWbuf@#6cx6X|eT*89t3;Wl9`wG|tCYdO1qyll4Nr5t-%Lf6+`nWND~ zP^#*D?(L*o+^^!_RF{b=d<2r{wQEQy$jT*IkL>+kRhf3t6kz4I>j*6t+^(+C>)kuY z`lDcjs&QhZUFu~nx~HY?pog!ms%>l)_>r~|TLvc2rAjkO>%fit?+ji-JHe^d7LTfV z+4)vRTmu>bGrvk!9l0t91~!brf7Wt!lMvY7cVy05{JN#;N<$O`w^Ox?0dtDy^4NA~ z?n_2whQD&(+MwxJyaCYkAFw`S$50zGm``+F&g{Ix-eH~ih~Z(QzDff=WH6hn+;pX3 zxjLXiz*Pm1flPu*_|zN3iH9ay=rL=5|ilnO`(?k1~MZHwz6y-|ug3 zRChOUw1^ns`VO0JwdslhUpbdq{u1_XT>}NQD@Rj2C#lxtG0!GE9`#?9=MfArj`!_* z$H>JBj4{Vz6%O!w)H7~zn?O`eZ>u?on+Qp7+WMcF0C*38qlRojz z^B^f4u~7P~p^M3#2R`w(oTLKnj1}DctepEVj%|V_qgP%6-e835<51!W)xZ#$;*e{A z0a5JT_5z454*?%f=^MB&nP1-7Ubj+7XboD1H-U*lk&W~lz4g>jME8hD&oUv`xo_CA zMy>z-T&Q~Y;<1`$ff3hlKgU~SDj2C0qsyTt^>$m)qWBZ}t_Be&y9Wh6cwK?jmnQH9 zQE|?2NC%yz&T}`#UfX0J*^zFgAc+_xHmpwRVqTWF@})ZCql5mD)Z5=RZxY`gu;|=S zi+v!Jjc~OjvzSyF|Bc&AyC5L9{{u*&F7<9*nEidSeh6E)E5qF8$8YW!bVov%3^HeD z=-#YTKp8aoH{!H7mz(<(RQs0XVP_1guh^8>PsE#8hFB-;t{UHxAwxR%M1ngNIw(t$ z#jAl?hHq*8TVA^giA)J$_^8Le6BekZES|8ReW|#lb9m^a5!?^At{V!e?MoNd`gw+# z_8T+Wvx{y3Pb6vLx?y3LCNN`ygiZ5t12ap;(+K*0|DL0TN9zkO*}_&E z(27=X(PA>4Q)|M2eyohNf}}5NcmjMq$J7=gL=u`?i#^)Ga3NNcH%Dh`_&R{<)%~N@ zlaX5-y3@z$56J)EIKsJWZ2XmicSEZVJgmKn;@av0dOE#poLZTX|yLXp|gNxp8`f0Aqt zI{y6Mt?0kL-{9sXMV4nN%us`<;XZBq~x}Fwlw>sE3k*;j8g{5NgygMJmptyTj z;_ld`2YK|!m;&`6axD!=@;M#E$;q5jdJ9ktKv~XB@5BL>T9e;WW2CGrf1|%qUy9(k zufu%DRNHX&Ukg%S`SMy#xpaBX?zOCc4M@Y+d52JZr#?a)8Gu0M6!4-k?oAq;!R*bP z&~X?QLdjK)5QGVVcHjLI;}+Tq>#s<|XaUhh=4+-3!?oh8(^ui7cWuR# zT6T6Wx(pj^1X)G1LP;erPzHp~5I2tQWS>84XW#12j2g2-%Q)-F z?F7tnT7Dgz^NRJRdJ^PjtNlgZY$UX*hC+cj!rgcGkp-m3^L4k3V|%vYyeFJ(*_!1M z(`V%Fu8zr5y&eFm=SF5*URTbxTu(fVg$RP2o94>2Cw@eYrmWHr&6+z~5Dk^m z^$3O3CGsNe!VF!sNE`=k#)nEk6W3#@UjC{nkq?+pBrS& zv|sX=iiurQu`kvd9N&Fjn!M=!5q5nAzr61HA`IC(tFe(e5!Tbrc|CE}CvTgthjvr- zL5|<0$4l}lBP&70TTiQij5zA2LxkiyFA{_ULBq%_yhd>a;l$8*b8dXKTjtB`r+IAV z!_Q%!rQQl*rT!^BU9_lo!7(D{t`og?Q!Xs69~^4>nsrRJ@4~ZwHctF{BGQns?>RAi z6n|i0qH(4}dN?CVx z6Shjs21gT<*qX@jk%T|hQJbT(`%5m*!p6DT_H0Qz3*{2(7&V71+q-#1QyZ75(foJaqk@}+b$o2m7BDjvVFj;o~h-_2{df3E@3h3Ti(Ye(3w(vrcs}4P( zelI?F9%uM)gwcDZ__{X%C#km8G34kvPwq-KK^z0250Km*UNVA?KkD;RV0wP~PxH1_ z>13La%whK^3Ou0BRg0A(tQP<4yrLF;{<=vp=yq&+V<3+5y6kM2?FN-apcSf#0q><8 z%~?u&D5VbQ0t`(e6()!BX_@l7=KC2#V!)wGJkPv-e{@EUq6jt5;UDGLtHRW`yzieP zxJC7}8n#sZpFEjf#f>A1j|9s!5GyxgYW$%loa;H2Ir5K>-03))%r|P+T%WUu!30y% z>?9vFI_>1UXeHAijLn|+o2#^x?AbNZ!4F4!wb&jLHR=`_T;Bd_XyXlW{SQl<3&502 zmFpuFXN*SlDYiYK^`;v+qvQ0TupDu4j74@J+n4^etsAose(CY2Ao+o(#`kTVf2$c| zqTcL2qnBEIgc7)q(B^UdcU^B}^C$j@APsoMY`bc5W*cU6GvS^scei$G8(}V)>`4~d zmG-a&^9;NHCtRhN4dZ*o|cT*0zb3O=loL#zxh)8dj;0t0v=+%QTv$>Yp3qN7IR)Z>fzhJRZN=; z&DPk>9cO}^>fw!#KQ+%995npuT`%Np3%++tlnAb&#Ubj@6@f9 zX;PjhluZ^pv*;1?tBCx59uQY)ZE2y&a$0>`EMM2`r15h_ zx2U`b3d1F!Bx0{v-5YBwMgFb9fh6VyQms5!?7o}UeU1VFk#9|_a4hv0hgMgtslP@% zi;@&uj_C)$A{-GV{Yc5L?he};Gu>Lqzm$VzeJdUrOn9<2<;pO5IH{4VZd@oA6(Q5E3 z?Xo482<~+7YOQta$$*n8Y><#N*Qo}UxC+(zzI5-`hn_d5SJ_xAhH^{bP;D638IlF2 z1x>iRyM9rXyyT>J(#(gwX3fRRbmD0e-@WdugpSfv43W`1^L5>EL z1d@DDEVM$SW#?ls?-ubU(;pg70+(&c_IF*sD`&UDZTBK{q-?-JF_ZtLV7;pWDtz&i zFRX@*Lu{`^VrM_iq6ct6)7^@LfSGTZl^K&hp0(UpV5OTz^NaKPcm5D!2Z*=c3qGmnS%tGzcgEYpyqw}NO&@~v-cLiD3LUSj5 zLDJ$^0K9GsxF1r)OIl9 z8h%xq_z_H)Sb%K-&X28||EpK?5nTuF5C8Nc8{H7vM|;WSf28C%Vo&wSZ%f}eTzU@4 zaw^V}y7gAOQ9rjBa|QwVFcZ_uTN#*JljzUh;N>YR)OyaI%vn_pwpi$_LhNf06QU?{ z47=2gI&jNC52zs*t0o9>ORf7pB8Y_V1=-kJKXx?i?}6)LLBV8=MuA>l~gO{9eWwWn<~H4^0*TjZGBjb7V~q*neS-< zujDY7zltn3-GkyJWEdXa_h>Gosz@&=3p|F(?fD&2jWC0JMP=(}`3g$h_?AB6@n}-v zTw_0jt`1(F83c~(03@<}f(A2B$K5L?iMbuI^_{%0KXupJ+*8a;t<|#RYTlwiaKyZ? zrM>IQyZ{Dl(K+`yi|=^4mv^aa)?Y)&N2b%60ceuzZSxpe7N(9|LoUyZX%-v-Q1~lJ8KHjjjApV8+}N{L;JJ5F0S)ZaR>xA+g5qiJ z%*<5Jv$2ADJiXZ5=y@|xV3z+A+wyPie@^qo!>vW5X~>sa#XzXZTIO~1XE{V{SZk}Z zv3xd1I;+^ID<=!;6xW*O(`UOZmk5sk?=8CB)JBFh8kNkNp*7v7O^$Y&&U}G4FbZ)1 zd58>*oi@24B`VqYJI6#{dcPq|D)=9u4kWWik?u0lZttr!C^8cujLCG)c&*cN=k?Z+ zYWAh2aR6Q{N;6vhxV}dB83pYMkP)b+jvwdgO^>GNhsaJIS;T@QtE#4T+i`0-3dtz; zQxIsK0NNN_j>8PB2^2w1d*fKnXF78#h zSeyrbma_nW1QS9eS`W%9cIsO)J-yrw&|v8{d}=e5{iu7wb1BwRQwP_mXE1*3^1oc-IR^9GlRz zF6N`TIkWfw{n*EB#13;r8nfS>`c(=ffcA6wy&GfYZ+r5A0<|4O@OLIjFFhjP=>HK< z#T4-rB6v4OgXd{U=`Q|^%+Y79r%bXnq-8W*_y@4qC8pW1#9ANU6s9-gIW6qZLWita zb57`>^Ag#wttFy)nhh0hHqeyIQ{a7%sG?QToT;wcNwhzLqsKHiP1u*s)UD)b5Pn5m9nlA zgVE=Vt1iHw&Ku8Uu*s?;XsT!OnFz^uW|HDg^P-~FA3z4_C7pw3>LAj!qqHX*hHpiK zFelXta!faO!MwAn_e&#A#_zgDO>2s}YerI{ovxZ)+pZJkj#p`v@hq)JR*Mn1=~V>4 z`~%{x7TDh{WlZn_{K=VUtVuxRv=9REzDEimOXPsc&X z6PCM%8~f8*1^)7!y&>6_pAW``ad+OEViNVdi_cAK!8XGFxHu+^vRH(XzgNHPc(4GX zO<}WYA8t)n{OPYH!)kufI3=z;U#6Tl*VQpIog5EX@QRLDSgg+J`3e*Bu2^osTvsSl zCj|y;5?3agyT4-()^+;jRD`7eeRd#_r|&oLDYf;T(^!AM{;i@*PaVSf?JX)QQuJ%d z)XN)Wv;6L4%z+_&78MC52({_-Ym@(jg82e@6jJxE<#t>qFf9E0x8{Fv5)&2My4n1- z8e4U7n&OBDYHE96a}D}k*2S8am$*>_&^lv~bS8uh$djSqi>Di=ZVWE4A15WbW0R10><>8~#PCC#)OO-qpuayoN=GmX{pkdh`& z=-N}i7gOZR5^!4kll7w$LKH9N+l$JvQ!fuhCPpA}J>G*)Y9v*mGE{A|`|7#vy$IP8 zQ9V@$B|uT>L;t)|37DQN(45}w{Ao83Tjk(p+HFi0_u}HBU))-bnTXt(zoNdqLF|h$ zuRH_PyDaZQFH)Q-E6K9QnfpoMprJR0e5wR+=Nlbp?CD>>V*9;>R`T)>!>L|b=DF?V zMTU5KlH$Q+i(=34a1o+Jzdh;l7n%6Q69F?D1w!l}05BedO+ND6i!rdu6cuxzukDO8 zynt}Jo5XfIdCl62q3aZ+$P!BDX2VzI(~F6A^zg9TmQ9p4cBv$@iyF|y>oT$~UveMh z|GZt@o{~0R?oF!fSY|AJiLP-<9J#vOJG^i1Cy2v5ui!@vcHJJmeBdp>zO)snn0Q z#Atv5(&?X%RvFj|mrU5Fycr+<1Z=U>5$h>V=5`~0Fhz>f@EzRXV=?*RJO;?ASrhAx zug@17f?`gBLswBh9C1t5qU&Z9`(OQ)@yp-Qe~dMxo;2mDOX#>zA){lova1P=ob14F zUZ<{0sAHkI@7b&(NA6y(sF%0H8A;I3z3X>0&ZZKJnBpf?zhh($CH@0As;-PLZRT;$ z74?!{SF{p}`~%=jvb@m-W^hgY3b$KY*}E)*I%#HwWlT$-!zq`gV*D{-qhh;qC4A(| z!L{Z&i?$6+CI0Y{fl_%gxM`AQD!NMb^7WmcLFBH{-d_&2BbpLWlsYbuZ|TspD#}KD zN^F1_*;3C{EdEU<)c0Eg_ah^Fc1VWM`7V0ZTSi{u@7G)6D}S2O^AMl0@^O#a5xbFH zOE{XzDqKmXr=N=O2ob#P>4oSsgl>(`)1=acP1ZR(bLdYAjSpc4*uVS8TrqOl=^r*M z8;OAqg`p{$GMV05ipIF85A@sooHn)eYRjyUgccYi7A~xLLP&ZHfPH;f?Bx$UX zXi?s{dn$_dr)p0{Y`*31i>l!HphE`tjlw`5E*=}K;f-Q#V~b8^EfH+5nDNLwY0Dmo zzBkyIgww{%@ZOZtoa9%@a~q{og|@XW_f(i?+1xLbwUcR7i=<6=(Hb?7_NAP|9I7+M zAuko6q6~i}TBW1Q*UNZC>W|9Aat^U+>CgEAnT&IH5}-54 zG9G7$k_gV!fUXw9y?);ghz-4)tERY^G&@!g2<_bq-I+B!tiQe(YYfK`2JlAhZ~X|F zx}w`L{c~*JOk=ibuQL?AYthLzlANm>4Oud+<`zydz}JVivAfZchbhT=yT_5lun)D0 z^K6e>$V#~>mBt9{G~{ZJa9O)dN765AQpFPa5aimq%_&`GVB#-RWo8M0cCw9iMoh~j zI(zak6Y@G)%M6XNp%R>w`0# zc79+%S?_D>@F>cr69%hf(OTlEpwSS0ygcD3FC=0GJ5Kg9f~?@B`rs|359}Rrn0%wg zr>W^P<@&<(E3Rp-6!}6NMg9j|XufjPT7Arl9@9Mmj8H(4sDqvUMAc9BN!mbJ3#t%b z06aQ&jg~4U9c!?vzQXrhYT-4_m0*ix9pCJ1rkj?@%KTJL+H(atL*;=PweuoTja>&; zf@VToe9BCi;>#!^s~$Nu)%ul;!CTE2moM^w7h)5Wqbr(>H`owmTQkdDrjG~LEF?x= z&!-KGLURN&c3gr-Heu14#}qW6dIshndEA%fPVU-2L$RP`6X|<`=u4~t7cr8<5tPxs z!EqdLzrCa=e3VG zu#>5ah+eDmg`SiUyf-^-@u#Zn*q8!vlGm)pHvOmLkrMlqDock!vGV?ti`PFut(phw z)&q5)4l#_D1Q6Cet@Dyjd1UIqu6cN7v%~(2FUr|zhVjANg%}w!XK=iaMlAU#8=9`4 zfx+o-3|efYJY3HaZE0HV2j!!d6a_RZD1H7>$k7ZM!_qUD$tWP!uo6W?T{2_c{XK>5 zM9L3Fum?d;^~v>j1%RI>e0KIMarz9Mbl>41Z@X2s`cu`(@oK@*9Wb;#-`jrp`jZ%9 zGe~SGpQ8#GP586Lmo0s@0F*v@{XT}rTokWL$`3;eccZvOwEJMd8m)7ky;g=uR#qxU zRzSrw<%tT(-dwY4_1IRcDGRdhFJM8NnYyvtl`z)-zm4~Rf9wBaq{h6GinlMZIxq4> zRYqR|UU6dmKtsgkJikEln{s>`_?z7e%xmQGKig|;5l=v_Hkza7157K)^i~}ICe<3g zyHmjaLr?JX$LQm77#T#QGRBob4YOUdvd~8jf#Obfpr&ypoC3Hn>;1A0<0w zzuHystrA1#@MU3C@-Q%!%_`h*38+tpcJm`=CYft!z+p<=mRNStDCc`-hcQgmoyAl3 zp}D$bIw^>tfItOmX}H8Hah_6I?r)6seZBiIc23%kWuXuN?Au)8Nj#AhMkY~z4zTnJ z4?pJ&HbID>0Oe0KpY5lih?8uCFdr}w{b?$et%ZO?8+=&nOX4y|_?)Bf)KV1CTBf|l z*UK1S+%zT$R}&N+=fXWpeKC)FnMPi7E}&RyZOTx_<7<}ubOA?!hYb#mlGI-@TNT%# zNB=68{P55Pw?$jt4B>B`90lpGxMib=D(2g6tw0S8jes|duLGNnW1-Jy^M|B ziUPsPT0&AtF_tHG=I}Eabph#k-B+em{c^d)IWb;OM^LQG;6xf`!6SEGPIdTS=0)jW#q-;+f&Gb6OTGEH_PVTWN*{Ef(7AEf1T}r z*J@bJy$+X|q^NRENayRbv*Jo>nJSx`#HiU9VYGK{;WZwWtzy%EHSMYPcX@+}uP`>m zw}rU?N|G*%Y`8N0>K~^r2zo=%&Y0xWQ!BYjrk0%c7x=X)z0=82_@qMBcOyF|Bi2O@WqZYyDfb z!_&?wnD*(E2Zwp|+Wr34mzST{35`>Cy*Ics6<06^$Sj2#cX57BS2mA>?km$8jw4|s|%_g#=sx^Y~vJIo!k$LS{ zIbo#%0$Ntrso5gNYZ|9S@CAX$@s!+e(Z`d?-AEgLH#AVK)?djP75}O!27U9vh8-iS z*hLt*kGu&K)VrW?g0HmQtwnBAgf2Rs=Qx#D)+|?6(^q5xvKJr`$GS&X50479aNdW> zZsBG94*g_32}&B?BL`Ka1h@qGnknlfG7Xgy{B>T-8y-`H=1pGT>fh^?%W12p9td>a zxKG@uvJwv7K%U@Q7`A01_Sy(9p)T()wNzYP7t#h4A&Kplk z`?d-fC;F#NTX|XVSDgU8u_CXG*VIaucQ9GBXOGap3U;LnZ+m8rzYmo{ikViLV2tyNa}fuSR@# zGu~A2{msdurht+lJ=?Eq^n!W&$tNt|`>&M0M1-HQ_n4v^#=hgnt0_k&|89A?`}#u_ zth)M2i#neD0l|jo-zm5HoPWBj=k2JZi1JMr-%LuM%7 zI!~96?9mCDl^$v}t7C9Ha|r9iV&o35B$C2^8qHuq5{OzZUQU60;0f--Qd#lIfEa+^y%flJdiI46lpJnxK$f;(PXCXMc8$Wx)SC@M* z?qkv;jknYizn%)ZC<{~$UN*mY?-U-D8C=7G9{#x6xaU9|VNH*JcgC=l>8^N1N!HIyEk2x?`H2Fm=fRBWfeR*N_hV|?3^g(3Jws@5Ol||@S97A6) z`Mpui_5|u16~TE&FD#MkQg99M6Gwt(q71*pLUGwVDo9i_L*sPwUgte&`Oq3_LiQwA zBi+s=z-HchH_{W_$sDpu!cyoCdUAa$>YH*;+JQAVehl?C8yEE~*;2c086{lz@46cR z2>?BsYm~ZBy8?7KSUe^Btob(MmOZ$*w^1UL>F=1kLZdFgIG%>;arZ;xu#8_LVx!+K zs`1ni?IUR`s!LTmkNsCY^dYzUzVxp%=BuIvtBGt)isf?~$tMGdsc}s%X#TjN?;zCm z7K`{sm8D)37vuHn@;N@+ebr}jywVfz18TWt-M10r6j7#@TwJb9VWFz`e)W)Zy!QK= zF|VqwMIp_n46xCTn8u9;L07^neL7d-^6@W?OXd63wrdP8-kB;LkRN&MW&f^+hQ%J= zXCy!?y(miED-gJ-T~@U0nHlqDo==+=>kN88yD{u82$9})9%mq z33c;NI!{CO&})?rYKS!@8xfNwPRwHsGt#O^65@!YveXhMjzP8_4!MblHrc?soIDtF zygnHk>69Enu<_DJ0EppP9|xCJ_RytoQil(1Nr!weD-5NXb{na#U2X+p8I464g%4q0 zBi#1y-aO^1J{%uiQ&MK#p;0aP6B(URou?TvWC7Y50nf6nMWZClV}x`e)`QGy-U+Isnv@m!BGxfJKDiZI82B9WZs|7VKR#a zBuoW9KvtZr{3iKp0FpI^4^#Jfc$;hFOer_i1j6_@w6Bryw}d!q5)NV8U2mvl6f|s9 zA`5vQ(~B0zW2Ka?6f*I8r2VplCT|?6iyA z4yGgc2bi4w8N8jew=x?ihRE|cLpg(b>0@R~Xt`=NzGAy*?Um8TAXRxY^U*{c=@+;4 zz!;BaPiMgquU!6{jgtuIGtbq|kc*W~E;nYXuce$|igIjEcsQXnRglPciIG3PX=qu= z@)o$c`L3HSb1@tJcfVC=eDh&VIjM&HEy|U%_tO|S^#WXa3Hl9t3eo4aQU1>q!#d*L z*m_W_wPMyG#%8u%@)%ivp+;?56U^-3>Y3?`fo5>w?QiC>1_hlai#laRc5NHU;DwL> zSF8)$MHxZ7{5Ed{DayVQ6R$+^zL$jjq%1AE9xTh`y7}Fzy$Qz~cUNW=ACu_M%@Da2w%gJ<=s&&MhI@#o>teVs;~Lh=w$T2n&HPD$PvMFsTA%)9 zhTY;WaZEF+%V*@6FjM8EyYTtyezh|#bJ*wjI~a~;h%0;QRt|f#Xxz_5i`FfmT{g)t zO)kF|z2XIot|FtLR3f7MO?(9Elr5T%PFRG3d|)+i@=KIK`VX4B2dI(L=qBfj?`&OR zZ)2iRRj5jJ;RZ+kAz+}=>{kj3W#DkYbNdL4n^PgY@%GsdIhSp$FTYx8A>yM>exZ(S zJEydf4?(YnO|l=W?T3b|oDj8EzpEk+W{oTmpY2~61{^$?x1|}VbM(^&VxF_5Ae`2U z-T1dHuPam~Q`B{{U-#VqB@Ow?8h+Nb=w(Jh4GBO8%UKvto5w21SLirCftgGUtB7c& zs&nG&!CvgnT;6kmyFte$K!M&b*@udXOAWCyqnK9q)G}+zKu=%67LQ5#&VLP}N`xv<_cLl< zR8365^nj}%5sv z5ntBSnz46ZbY!nI#tH>rbYlLJ-0kW(xbFKH55_b0#wK?X*BUW75el(I15&PcV?ODkLqO$B82;$NA**CG z5-;nGm}clKStWK1hzIOB%&7rC-{`GC&Pk*V9E}exj9R~a!qYx+LSaF-PCfX^PRjUF zUy|6FFCq{CirDY#8dd^|cqHhF+nXoqRg||)vujT>Q@zVYQ={Z~c)tcUzp_nSHj|H6 zpZ0M7-`je?zm5N)EZ{0+itvsHfOuS^t3Ip!1MDS!yZ{=o!JwTVnJFdGUMFGla2Uu2 zcK^9)sTD{$z3O}QdBU9an0s$%U)9Y-H&l#f?^BCt`lu*Yi+YsdHvtB2GL+)Hc_7BD!|hW(i24yPS^I<=WrWpum-fyP4d&+ z+PH2gH)ynjzkoNov7+a-oYfve_KZ`PMj!nQ$-4L(6(?+VC5vUX{ou`yj!8je+4mf( znbZgEZ1Q&cnvV>`s`dQf%@(rEH?vkgnj8SZ{y+RirB$>X~+<$9tz zbki8mr52Zr+58k(zoSJ9Ef(^miYFqSXIWB;i#F2Z=J2nYN!#RkAqk7$l7|@q@(%Z= zM-&?ebp>l$-k4H^qcDlmm&FLR@4YnUOCnl86(zwJwq+T_j~pT-f?Q)=DS`XCjb#>uFP{ebww zbdzKoaNV@(l7@5< zNfC(W5X_pb@{*|&(||X-I+v2&N6`v=*H#i~*z(5w!O02#Ezfc2k3F6uj3#->y5|PJ zZYMLe3h!O#WCL|JyihDZ*$yQLo!(W>{oSCIG5{SsV2^5I*#cD&@adsEo5z*&F*r+` zfRGa4Le^cVQ66Q=3kOy~;(PA~CX-hFlpY#xrSU@%3kuvgEbEQzU>Zozjn&lar{|cE zbYY{cf=Ug2b{|n79@V~H?$w59stM9N7q0 zv(BehjqSgg`PFyTl&mpCkHnN&ZLN803IXIWz%#gXYD`tI4(?U(h6^TZyX<2+QBer; zditpw^g9MYIo%ttZ#H-i26zl_n8c~-D?BQTAy~X_qm_@lxh$?umhQ0X!=0hvRTXw_8Ur`Gx~ZzZnSlWXOUyZm?o$vL#V8N$0D6U4-{ za=7e;b{}P;D$49acfpI0(~EfZMS^pqJmI-QCMl>rkOwu-rn-uvD)NGx*p|%jt@0on zU|Z5?GqY63rdci)R?!n&{haHTUe0AXzN@~ecjlhi`I;}3Pf5ej8oA83EeE!TWYwjZ zk|(Zn(>AN>N=>8FesvK;k@X>oZ<$i={0Wzlya0j48}2tBez&^4zm`?xWyRgEg=B+{6h^0SsC{?TJ)Fntqn2m zAjAG|F&Po|sN>SCYvDHo=_w1&Y<;IbZF3eScav5+UnmC=yWGBue-`0kvQd5>Fq5(I zfYsX`1oJb(Yy$B|o&p-C=6!8R?JvJpzC9}1o8_TZag^tXW1kBHoXTn>H>-m9>UYRq zu|KR6!y0SEZJ~z@3W>)4_%U2F#TWzHKh=WEh$KnTaba8rr=AO38I}y)mn-mR)?W*U z@;x{c#!EisapR))YqnO!<(Ifj7`l{=B$Z|w2XnYj;TJm^1vYt3J9kOAYjDk?zM}hw zbr@gQE54&0Hq;EHL^n0)@-7m-NN%RSjA~~zqI(U6X7oi6)=!ma8C;+qunwRUrtox= zuVEg%GwoVfLXE@voo(^8K-&5C8@y*VYkE=t!=XH`E8`mCTj>kxjr5qY^xf~L(*d~$ zx&qGRj9+fa>I>_t?i}$d$Z~+#i>I&QCLti)9UmioX#H8!Xb?*4J63= zwafjzOx|FHbD!a1m3LU>^t?mE%;}!T#=En2FZAaxr;T96l}%`Hjfw{E&%D!TGeH*` zGs!19i_>4h4rN>)^-{vovRYJ;B_u?<{M6b&>161r;`*&C=wsc6p4sK6^G`Fgq@L`V z)GT^ggzm3bCd0*lWs_}@nN0E)AN$Ciy8l?2ilp~dEra^2#dF(w&RoT6;5BGHV-&@F z_Qhlk!22cQ%@<_C)DHLMZ@9s=K%dBCzWn*|q8mhJJANimAVpoFL$H`bO4TRU(SWh! zHQ+Z~EMh0R7}9Z{h36Td@fBY>H)*Q}r!cp> zRdF!=qmQSWd8P`?Yx{81aO10XM7WIWkAD}V2BGSW9(qsB;pey7zdt9}P#p}C^I+6^`h2uP0_|Jhw6K()pBG&U6sbE~eAxI|iUaKGNRp!Z8# z*t2vC)ycU$Ig5sRNs#{8ia;H3#CW+?QfOR0N>#3KekOT{B@Scvi6WA!Y3TWkxr=J2 z8b(#7!Z@=6c*n-ox?Sj1LrFt+^#XMmIeZy0l0U9vSMpG&O`O8TuOwc()O^B-4m9)R zOTZmQ?EJZIn4gr0zw@p!+)Cp%0AFSa%i6^Zl55Dso1kPPunKW1e_*O7q?63igH||j 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

    iSzOzQa&N*X`0N-K5HU?@-y#ilU5VX&ES- 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 HN(?x(zi!%;qO(@P+57AjTILK2aBLIUISR+$ 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 vq%%Bt(F$ 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

    uSik*A;d-uREH1uo1AJw&>n*68K0K;ON$PuE^8; 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

    p!=f`yG)Op1nVNmfRox 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�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 Pzai@Tf8yK$ci;aT*pt@o literal 0 HcmV?d00001 From 24f2e1a68991c8c92d4fee987526eb3e21e1defc Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 4 Oct 2018 20:46:08 +0100 Subject: [PATCH 097/381] 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 | Bin 0 -> 42798 bytes ...e723-Ordered-Interleaved-Progressive-B.jpg | Bin 0 -> 36937 bytes ...e723-Ordered-Interleaved-Progressive-C.jpg | Bin 0 -> 46799 bytes 12 files changed, 46 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 0000000000000000000000000000000000000000..0a11065ce9518e64ba026484e37db6ed8fbdc2a9 GIT binary patch literal 42798 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�ZR-qL|*^ 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..eb52570e1c02a6519c7240efa30bdb55eab1c32e GIT binary patch literal 36937 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 &CAy9^I=!+U4%+B5%Cz92ls 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 m_Y7NT;k^)>6=fz?;%urin!cPO@SY)$% Date: Fri, 5 Oct 2018 10:11:05 +0100 Subject: [PATCH 098/381] 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 99e773c13e86a812b9ed9f3a598476553cddbcd0 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 5 Oct 2018 21:42:42 +0100 Subject: [PATCH 099/381] 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 63e3c4411ae8802a5d465ddf86d07571b6b72e04 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 5 Oct 2018 22:01:56 +0100 Subject: [PATCH 100/381] 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 63ee5970220c6889177749dc14228cac035fcee9 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 5 Oct 2018 22:28:48 +0100 Subject: [PATCH 101/381] 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 26ea2af4be2a8bf3083675d417e1028b15db2457 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 6 Oct 2018 13:08:15 +0100 Subject: [PATCH 102/381] 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 298a2f038e8d97c231bab325c03f07dfa9d85d40 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 6 Oct 2018 13:28:27 +0100 Subject: [PATCH 103/381] 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 08dfb7aa2a14af3f5bdb552acfd247822d9d4a05 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 6 Oct 2018 16:27:27 +0200 Subject: [PATCH 104/381] 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 eddbd220448a3a7d3d90710a5f4495924aa054bc Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 6 Oct 2018 16:50:40 +0200 Subject: [PATCH 105/381] 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 36abf6d116d16a24c4c93b706a47fec527a29007 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 106/381] -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 afe9cd14e2b7db8c9faf92c68e818e3709fb0209 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sat, 6 Oct 2018 22:23:41 +0200 Subject: [PATCH 107/381] 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 0abb99b884700bd892f7a56a7ae722b58e2e52af Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sat, 6 Oct 2018 23:16:13 +0200 Subject: [PATCH 108/381] fix whitespacing in generated code --- .../PixelOperations{TPixel}.Generated.cs | 140 +++++++++--------- .../PixelOperations{TPixel}.Generated.tt | 29 ++-- 2 files changed, 85 insertions(+), 84 deletions(-) diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs index e8908fe05e..3ea4007d22 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs @@ -1,4 +1,13 @@ -// Copyright (c) Six Labors and contributors. + + + + + + + + + +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. // @@ -10,8 +19,7 @@ namespace SixLabors.ImageSharp.PixelFormats public partial class PixelOperations { - - /// + /// /// Converts 'count' elements in 'source` span of data to a span of -s. /// /// The source of data. @@ -19,7 +27,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void PackFromRgba64(ReadOnlySpan source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); @@ -34,8 +42,8 @@ namespace SixLabors.ImageSharp.PixelFormats dp.PackFromRgba64(temp); } } - - /// + + /// /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// @@ -47,8 +55,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromRgba64(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - - /// + + /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// Bulk version of . /// @@ -70,20 +78,20 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source colors. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgba64Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) { this.ToRgba64(sourceColors, MemoryMarshal.Cast(destBytes), count); } - - /// + + /// /// Converts 'count' elements in 'source` span of data to a span of -s. /// /// The source of data. @@ -91,7 +99,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void PackFromRgb48(ReadOnlySpan source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); @@ -106,8 +114,8 @@ namespace SixLabors.ImageSharp.PixelFormats dp.PackFromRgb48(temp); } } - - /// + + /// /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// @@ -119,8 +127,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromRgb48(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - - /// + + /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// Bulk version of . /// @@ -142,20 +150,20 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source colors. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgb48Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) { this.ToRgb48(sourceColors, MemoryMarshal.Cast(destBytes), count); } - - /// + + /// /// Converts 'count' elements in 'source` span of data to a span of -s. /// /// The source of data. @@ -163,7 +171,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); @@ -178,8 +186,8 @@ namespace SixLabors.ImageSharp.PixelFormats dp.PackFromRgba32(temp); } } - - /// + + /// /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// @@ -191,8 +199,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromRgba32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - - /// + + /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// Bulk version of . /// @@ -214,20 +222,20 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source colors. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgba32Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) { this.ToRgba32(sourceColors, MemoryMarshal.Cast(destBytes), count); } - - /// + + /// /// Converts 'count' elements in 'source` span of data to a span of -s. /// /// The source of data. @@ -235,7 +243,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); @@ -250,8 +258,8 @@ namespace SixLabors.ImageSharp.PixelFormats dp.PackFromBgra32(temp); } } - - /// + + /// /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// @@ -263,8 +271,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromBgra32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - - /// + + /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// Bulk version of . /// @@ -286,20 +294,20 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source colors. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToBgra32Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) { this.ToBgra32(sourceColors, MemoryMarshal.Cast(destBytes), count); } - - /// + + /// /// Converts 'count' elements in 'source` span of data to a span of -s. /// /// The source of data. @@ -307,7 +315,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); @@ -322,8 +330,8 @@ namespace SixLabors.ImageSharp.PixelFormats dp.PackFromRgba32(temp); } } - - /// + + /// /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// @@ -335,8 +343,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromRgb24(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - - /// + + /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// Bulk version of . /// @@ -358,20 +366,20 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source colors. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgb24Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) { this.ToRgb24(sourceColors, MemoryMarshal.Cast(destBytes), count); } - - /// + + /// /// Converts 'count' elements in 'source` span of data to a span of -s. /// /// The source of data. @@ -379,7 +387,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); @@ -394,8 +402,8 @@ namespace SixLabors.ImageSharp.PixelFormats dp.PackFromRgba32(temp); } } - - /// + + /// /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// @@ -407,8 +415,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromBgr24(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - - /// + + /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// Bulk version of . /// @@ -430,20 +438,20 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source colors. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToBgr24Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) { this.ToBgr24(sourceColors, MemoryMarshal.Cast(destBytes), count); } - - /// + + /// /// Converts 'count' elements in 'source` span of data to a span of -s. /// /// The source of data. @@ -451,7 +459,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); @@ -466,8 +474,8 @@ namespace SixLabors.ImageSharp.PixelFormats dp.PackFromArgb32(temp); } } - - /// + + /// /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// @@ -479,8 +487,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromArgb32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - - /// + + /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// Bulk version of . /// @@ -502,19 +510,17 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source colors. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToArgb32Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) { this.ToArgb32(sourceColors, MemoryMarshal.Cast(destBytes), count); } - - } - + } } \ 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 5c762c7df1..dbd30560ea 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt @@ -14,8 +14,7 @@ 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. @@ -23,7 +22,7 @@ /// 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); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); @@ -38,8 +37,8 @@ dp.PackFrom<#=tempPixelType#>(temp); } } - - /// + + /// /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// @@ -51,14 +50,13 @@ { this.PackFrom<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); } - <# +<# } void GenerateToDestFormatMethods(string pixelType) { #> - - /// + /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// Bulk version of . /// @@ -80,19 +78,19 @@ } } - /// + /// /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source colors. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void To<#=pixelType#>Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) { this.To<#=pixelType#>(sourceColors, MemoryMarshal.Cast>(destBytes), count); } - <# +<# } #> @@ -107,8 +105,8 @@ namespace SixLabors.ImageSharp.PixelFormats using System.Runtime.InteropServices; public partial class PixelOperations - { - <# + {<# + GeneratePackFromMethods("Rgba64", "Rgba64", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Rgba64"); @@ -129,8 +127,5 @@ namespace SixLabors.ImageSharp.PixelFormats GeneratePackFromMethods("Argb32", "Argb32", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Argb32"); - #> - - } - + #> } } \ No newline at end of file From 9720fea2da3eecf14e0f2327728f47309e830df0 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sat, 6 Oct 2018 15:19:11 +0200 Subject: [PATCH 109/381] #718: add pixel types Gray8 and Gray16 --- src/ImageSharp/PixelFormats/Gray16.cs | 270 ++++++++++++++++++ src/ImageSharp/PixelFormats/Gray8.cs | 265 +++++++++++++++++ .../PixelFormats/Gray8Tests.cs | 211 ++++++++++++++ 3 files changed, 746 insertions(+) create mode 100644 src/ImageSharp/PixelFormats/Gray16.cs create mode 100644 src/ImageSharp/PixelFormats/Gray8.cs create mode 100644 tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs diff --git a/src/ImageSharp/PixelFormats/Gray16.cs b/src/ImageSharp/PixelFormats/Gray16.cs new file mode 100644 index 0000000000..a7e50e3667 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Gray16.cs @@ -0,0 +1,270 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing a single 16 bit normalized gray values. + /// + /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. + /// + /// + public struct Gray16 : IPixel, IPackedVector + { + /// + /// RX as in ITU-R recommendation 709 to match libpng + /// + private const float Rx = .2126F; + + /// + /// GX as in ITU-R recommendation 709 to match libpng + /// + private const float Gx = .7152F; + + /// + /// BX as in ITU-R recommendation 709 to match libpng + /// + private const float Bx = .0722F; + + /// + /// Initializes a new instance of the struct. + /// + /// The gray component + public Gray16(byte gray) + { + this.PackedValue = gray; + } + + /// + public ushort PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// + /// 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. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(Gray16 left, Gray16 right) + { + return left.PackedValue == right.PackedValue; + } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(Gray16 left, Gray16 right) + { + return left.PackedValue != right.PackedValue; + } + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromScaledVector4(Vector4 vector) + { + this.PackFromVector4(vector); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToScaledVector4() + { + var scaledGray = this.PackedValue / 65535f; // ushort.Max as float + return new Vector4(scaledGray, scaledGray, scaledGray, 1.0f); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromVector4(Vector4 vector) + { + this.PackedValue = Pack(vector.X, vector.Y, vector.Z); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToVector4() + { + return new Vector4(this.PackedValue, this.PackedValue, this.PackedValue, 1.0f); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba32(Rgba32 source) + { + this.PackedValue = Pack(source.R, source.G, source.B); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromArgb32(Argb32 source) + { + this.PackedValue = Pack(source.R, source.G, source.B); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromBgra32(Bgra32 source) + { + this.PackedValue = Pack(source.R, source.G, source.B); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgb24(ref Rgb24 dest) + { + var scaledValue = this.PackedAsByte(); + + dest.R = scaledValue; + dest.G = scaledValue; + dest.B = scaledValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba32(ref Rgba32 dest) + { + var scaledValue = this.PackedAsByte(); + + dest.R = scaledValue; + dest.G = scaledValue; + dest.B = scaledValue; + dest.A = 255; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToArgb32(ref Argb32 dest) + { + var scaledValue = this.PackedAsByte(); + + dest.R = scaledValue; + dest.G = scaledValue; + dest.B = scaledValue; + dest.A = 255; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToBgr24(ref Bgr24 dest) + { + var scaledValue = this.PackedAsByte(); + + dest.R = scaledValue; + dest.G = scaledValue; + dest.B = scaledValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToBgra32(ref Bgra32 dest) + { + var scaledValue = this.PackedAsByte(); + + dest.R = scaledValue; + dest.G = scaledValue; + dest.B = scaledValue; + dest.A = 255; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgb48(Rgb48 source) => + this.PackedValue = Pack(source.R, source.G, source.B); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgb48(ref Rgb48 dest) + { + dest.R = this.PackedValue; + dest.G = this.PackedValue; + dest.B = this.PackedValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => + this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + /// Compares an object with the packed vector. + /// + /// The object to compare. + /// True if the object is equal to the packed vector. + public override bool Equals(object obj) + { + return obj is Gray16 other && this.Equals(other); + } + + /// + /// Compares another packed vector with the packed vector. + /// + /// The Gray8 packed vector to compare. + /// True if the packed vectors are equal. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Gray16 other) + { + return this.PackedValue == other.PackedValue; + } + + /// + /// Gets a string representation of the packed vector. + /// + /// A string representation of the packed vector. + public override string ToString() + { + return (this.PackedValue / 65535f).ToString(); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + /// + /// Packs a into a byte. + /// + /// Red value of the color to pack. + /// Green value of the color to pack. + /// Blue value of the color to pack. + /// The containing the packed value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ushort Pack(float r, float g, float b) + { + float sum = r + g + b; + float val = (r * Rx) + (g * Gx) + (b * Bx); + return (ushort)Math.Round(val * 65535f / sum); // TODO: if this is correct, Rx, Gx, Bx consts could be scaled by 65535f directly! + } + + /// + /// Packs the into a byte. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private byte PackedAsByte() + { + return (byte)(this.PackedValue >> 8); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Gray8.cs b/src/ImageSharp/PixelFormats/Gray8.cs new file mode 100644 index 0000000000..db05395431 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Gray8.cs @@ -0,0 +1,265 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing a single 8 bit normalized gray values. + /// + /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. + /// + /// + public struct Gray8 : IPixel, IPackedVector + { + /// + /// RX as in ITU-R recommendation 709 to match libpng + /// + private const float Rx = .2126F; + + /// + /// GX as in ITU-R recommendation 709 to match libpng + /// + private const float Gx = .7152F; + + /// + /// BX as in ITU-R recommendation 709 to match libpng + /// + private const float Bx = .0722F; + + /// + /// Initializes a new instance of the struct. + /// + /// The gray component + public Gray8(byte gray) + { + this.PackedValue = gray; + } + + /// + public byte PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// + /// 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. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(Gray8 left, Gray8 right) + { + return left.PackedValue == right.PackedValue; + } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(Gray8 left, Gray8 right) + { + return left.PackedValue != right.PackedValue; + } + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromScaledVector4(Vector4 vector) + { + this.PackFromVector4(vector); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToScaledVector4() + { + var scaledGray = this.PackedValue / 255f; + return new Vector4(scaledGray, scaledGray, scaledGray, 1.0f); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromVector4(Vector4 vector) + { + this.PackedValue = Pack(vector.X, vector.Y, vector.Z); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToVector4() + { + return new Vector4(this.PackedValue, this.PackedValue, this.PackedValue, 1.0f); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba32(Rgba32 source) + { + this.PackedValue = Pack(source.R, source.G, source.B); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromArgb32(Argb32 source) + { + this.PackedValue = Pack(source.R, source.G, source.B); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromBgra32(Bgra32 source) + { + this.PackedValue = Pack(source.R, source.G, source.B); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgb24(ref Rgb24 dest) + { + dest.R = this.PackedValue; + dest.G = this.PackedValue; + dest.B = this.PackedValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba32(ref Rgba32 dest) + { + dest.R = this.PackedValue; + dest.G = this.PackedValue; + dest.B = this.PackedValue; + dest.A = 255; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToArgb32(ref Argb32 dest) + { + dest.R = this.PackedValue; + dest.G = this.PackedValue; + dest.B = this.PackedValue; + dest.A = 255; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToBgr24(ref Bgr24 dest) + { + dest.R = this.PackedValue; + dest.G = this.PackedValue; + dest.B = this.PackedValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToBgra32(ref Bgra32 dest) + { + dest.R = this.PackedValue; + dest.G = this.PackedValue; + dest.B = this.PackedValue; + dest.A = 255; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgb48(Rgb48 source) => + this.PackedValue = Pack(source.R, source.G, source.B); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgb48(ref Rgb48 dest) + { + ushort gray = (ushort)(this.PackedValue * 255); + dest.R = gray; + dest.G = gray; + dest.B = gray; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => + this.PackFromScaledVector4(source.ToScaledVector4()); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackedValue = source.PackedValue; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackedValue = (byte)(source.PackedValue / 255); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackedValue = this.PackedValue; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackedValue = (ushort)(this.PackedValue * 255); + + /// + /// Compares an object with the packed vector. + /// + /// The object to compare. + /// True if the object is equal to the packed vector. + public override bool Equals(object obj) + { + return obj is Gray8 other && this.Equals(other); + } + + /// + /// Compares another packed vector with the packed vector. + /// + /// The Gray8 packed vector to compare. + /// True if the packed vectors are equal. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Gray8 other) + { + return this.PackedValue == other.PackedValue; + } + + /// + /// Gets a string representation of the packed vector. + /// + /// A string representation of the packed vector. + public override string ToString() + { + return (this.PackedValue / 255F).ToString(); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + /// + /// Packs a into a byte. + /// + /// Red value of the color to pack. + /// Green value of the color to pack. + /// Blue value of the color to pack. + /// The containing the packed value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte Pack(float r, float g, float b) + { + float sum = r + g + b; + float val = (r * Rx) + (g * Gx) + (b * Bx); + return (byte)Math.Round(val * 255 / sum); // TODO: if this is correct, Rx, Gx, Bx consts could be scaled by 255 directly! + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs new file mode 100644 index 0000000000..c4ce7339da --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs @@ -0,0 +1,211 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.PixelFormats +{ + public class Gray8Tests + { + [Theory] + [InlineData(0)] + [InlineData(255)] + [InlineData(10)] + [InlineData(42)] + public void Gray8_PackedValue_EqualsInput(byte input) + { + Assert.Equal(input, new Gray8(input).PackedValue); + } + + [Theory] + [InlineData(0)] + [InlineData(255)] + [InlineData(30)] + public void Gray8_ToVector4(byte input) + { + // arrange + var gray = new Gray8(input); + + // act + var actual = gray.ToVector4(); + + // assert + Assert.Equal(input, actual.X); + Assert.Equal(input, actual.Y); + Assert.Equal(input, actual.Z); + Assert.Equal(1, actual.W); + } + + [Theory] + [InlineData(0)] + [InlineData(255)] + [InlineData(30)] + public void Gray8_ToScaledVector4(byte input) + { + // arrange + var gray = new Gray8(input); + + // act + var actual = gray.ToScaledVector4(); + + // assert + float scaledInput = input / 255f; + Assert.Equal(scaledInput, actual.X); + Assert.Equal(scaledInput, actual.Y); + Assert.Equal(scaledInput, actual.Z); + Assert.Equal(1, actual.W); + } + + [Fact] + public void Gray8_PackFromScaledVector4() + { + // arrange + Gray8 gray = default; + int expected = 128; + Vector4 scaled = new Gray8(128).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + byte actual = gray.PackedValue; + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray8_PackFromScaledVector4_ToRgb24() + { + // arrange + Rgb24 actual = default; + Gray8 gray = default; + var expected = new Rgb24(0, 0, 0); + Vector4 scaled = new Gray8(128).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToRgb24(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray8_PackFromScaledVector4_ToRgba32() + { + // arrange + Rgba32 actual = default; + Gray8 gray = default; + var expected = new Rgba32(0, 0, 0, 128); + Vector4 scaled = new Gray8(128).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToRgba32(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray8_PackFromScaledVector4_ToBgr24() + { + // arrange + Bgr24 actual = default; + Gray8 gray = default; + var expected = new Bgr24(128, 128, 128); + Vector4 scaled = new Gray8(128).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToBgr24(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray8_PackFromScaledVector4_ToBgra32() + { + // arrange + Bgra32 actual = default; + Gray8 gray = default; + var expected = new Bgra32(128,128,128); + Vector4 scaled = new Gray8(128).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToBgra32(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray8_PackFromScaledVector4_ToArgb32() + { + // arrange + Gray8 gray = default; + Argb32 actual = default; + var expected = new Argb32(128, 128, 128); + Vector4 scaled = new Gray8(128).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToArgb32(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray8_PackFromScaledVector4_ToRgba64() + { + // arrange + Gray8 gray = default; + Rgba64 actual = default; + var expected = new Rgba64(65535, 65535, 65535, 65535); + Vector4 scaled = new Gray8(255).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToRgba64(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray8_PackFromRgb48_ToRgb48() + { + // arrange + var gray = default(Gray8); + var actual = default(Rgb48); + var expected = new Rgb48(0, 0, 0); + + // act + gray.PackFromRgb48(expected); + gray.ToRgb48(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray8_PackFromRgba64_ToRgba64() + { + // arrange + var gray = default(Gray8); + var actual = default(Rgba64); + var expected = new Rgba64(0, 0, 0, 65535); + + // act + gray.PackFromRgba64(expected); + gray.ToRgba64(ref actual); + + // assert + Assert.Equal(expected, actual); + } + } +} From 0354f32c447c7a68d8509d2e9b97af8bbda34f45 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sat, 6 Oct 2018 23:23:39 +0200 Subject: [PATCH 110/381] #718: fix merge conflicts, adapt changes from PR #727 to t4 script --- .../PixelOperations{TPixel}.Generated.cs | 72 +++++++++++++++++++ .../PixelOperations{TPixel}.Generated.tt | 5 +- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs index 3ea4007d22..50398eeb25 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs @@ -522,5 +522,77 @@ namespace SixLabors.ImageSharp.PixelFormats { this.ToArgb32(sourceColors, MemoryMarshal.Cast(destBytes), count); } + + /// + /// 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 PackFromGray8(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + ref Gray8 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++) + { + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + temp = Unsafe.Add(ref sourceRef, i); + dp.PackFromGray8(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 PackFromGray8Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + { + this.PackFromGray8(MemoryMarshal.Cast(sourceBytes), destPixels, count); + } + + /// + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Bulk version of . + /// + /// The span of source pixels + /// The destination span of data. + /// The number of pixels to convert. + internal virtual void ToGray8(ReadOnlySpan sourcePixels, Span dest, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + + ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destBaseRef = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destBaseRef, i); + sp.ToGray8(ref dp); + } + } + + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// The to the source colors. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToGray8Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + { + this.ToGray8(sourceColors, MemoryMarshal.Cast(destBytes), count); + } } } \ 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 dbd30560ea..b4b577e3ab 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt @@ -127,5 +127,8 @@ namespace SixLabors.ImageSharp.PixelFormats GeneratePackFromMethods("Argb32", "Argb32", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Argb32"); - #> } + + GeneratePackFromMethods("Gray8", "Gray8", "temp = Unsafe.Add(ref sourceRef, i);"); + GenerateToDestFormatMethods("Gray8"); +#> } } \ No newline at end of file From 904fcd5c532ceb6c0c72f8b4ed84f5fe5da4ea7c Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sat, 6 Oct 2018 19:19:58 +0200 Subject: [PATCH 111/381] #718: fix Gray8Tests --- tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs index c4ce7339da..64ad0bff60 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs @@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // arrange Rgb24 actual = default; Gray8 gray = default; - var expected = new Rgb24(0, 0, 0); + var expected = new Rgb24(128, 128, 128); Vector4 scaled = new Gray8(128).ToScaledVector4(); // act @@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // arrange Rgba32 actual = default; Gray8 gray = default; - var expected = new Rgba32(0, 0, 0, 128); + var expected = new Rgba32(128, 128, 128, 255); Vector4 scaled = new Gray8(128).ToScaledVector4(); // act From 58a5232e723c0f573ec699934b15e94ec7e1794f Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sat, 6 Oct 2018 22:13:58 +0200 Subject: [PATCH 112/381] #718: extend IPixel interface and implement it everywhere, ... AND add unit tests AND fix Gray16 implementation (constructor takes ushort, not byte) AND fix Gray8 and Gray16 Pack (do not scale by sum) --- src/ImageSharp/PixelFormats/Alpha8.cs | 16 ++ src/ImageSharp/PixelFormats/Argb32.cs | 30 +++ src/ImageSharp/PixelFormats/Bgr24.cs | 27 +++ src/ImageSharp/PixelFormats/Bgr565.cs | 16 ++ src/ImageSharp/PixelFormats/Bgra32.cs | 29 +++ src/ImageSharp/PixelFormats/Bgra4444.cs | 16 ++ src/ImageSharp/PixelFormats/Bgra5551.cs | 16 ++ src/ImageSharp/PixelFormats/Byte4.cs | 16 ++ src/ImageSharp/PixelFormats/Gray16.cs | 33 ++- src/ImageSharp/PixelFormats/Gray8.cs | 3 +- src/ImageSharp/PixelFormats/HalfSingle.cs | 16 ++ src/ImageSharp/PixelFormats/HalfVector2.cs | 16 ++ src/ImageSharp/PixelFormats/HalfVector4.cs | 16 ++ src/ImageSharp/PixelFormats/IPixel.cs | 24 ++ .../PixelFormats/NormalizedByte2.cs | 16 ++ .../PixelFormats/NormalizedByte4.cs | 16 ++ .../PixelFormats/NormalizedShort2.cs | 16 ++ .../PixelFormats/NormalizedShort4.cs | 16 ++ src/ImageSharp/PixelFormats/Rg32.cs | 16 ++ src/ImageSharp/PixelFormats/Rgb24.cs | 27 +++ src/ImageSharp/PixelFormats/Rgb48.cs | 33 +++ src/ImageSharp/PixelFormats/Rgba1010102.cs | 16 ++ src/ImageSharp/PixelFormats/Rgba32.cs | 35 +++ src/ImageSharp/PixelFormats/Rgba64.cs | 29 +++ src/ImageSharp/PixelFormats/RgbaVector.cs | 16 ++ src/ImageSharp/PixelFormats/Short2.cs | 16 ++ src/ImageSharp/PixelFormats/Short4.cs | 16 ++ .../PixelFormats/Gray16Tests.cs | 211 ++++++++++++++++++ 28 files changed, 748 insertions(+), 5 deletions(-) create mode 100644 tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/Alpha8.cs index a8d97d31a2..d795931af3 100644 --- a/src/ImageSharp/PixelFormats/Alpha8.cs +++ b/src/ImageSharp/PixelFormats/Alpha8.cs @@ -168,6 +168,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.B = 0; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackedValue = 255; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackedValue = 0; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackedValue = 255; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackedValue = 0; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Argb32.cs b/src/ImageSharp/PixelFormats/Argb32.cs index 51d3964ef8..0249bb6af9 100644 --- a/src/ImageSharp/PixelFormats/Argb32.cs +++ b/src/ImageSharp/PixelFormats/Argb32.cs @@ -1,6 +1,7 @@ // 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; @@ -289,6 +290,35 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = this.A; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) + { + this.A = 255; + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) + { + var val = (byte)(((source.PackedValue * 255) + 32895) >> 16); + this.R = val; + this.G = val; + this.B = val; + this.A = 255; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// /// Converts the pixel to format. /// diff --git a/src/ImageSharp/PixelFormats/Bgr24.cs b/src/ImageSharp/PixelFormats/Bgr24.cs index fc283b5684..bc8e2324ce 100644 --- a/src/ImageSharp/PixelFormats/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/Bgr24.cs @@ -172,6 +172,33 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = byte.MaxValue; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) + { + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) + { + var val = (byte)(((source.PackedValue * 255) + 32895) >> 16); + this.R = val; + this.G = val; + this.B = val; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) diff --git a/src/ImageSharp/PixelFormats/Bgr565.cs b/src/ImageSharp/PixelFormats/Bgr565.cs index 570b975dba..53f15ecb3b 100644 --- a/src/ImageSharp/PixelFormats/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/Bgr565.cs @@ -187,6 +187,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)MathF.Round(vector.W); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Bgra32.cs b/src/ImageSharp/PixelFormats/Bgra32.cs index 233df2f29e..304f815359 100644 --- a/src/ImageSharp/PixelFormats/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/Bgra32.cs @@ -215,6 +215,35 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ToBgra32(ref Bgra32 dest) => dest = this; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) + { + this.R = source.PackedValue; + this.R = source.PackedValue; + this.R = source.PackedValue; + this.A = byte.MaxValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) + { + var val = (byte)(((source.PackedValue * 255) + 32895) >> 16); + this.R = val; + this.G = val; + this.B = val; + this.A = byte.MaxValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// /// Converts the pixel to format. /// diff --git a/src/ImageSharp/PixelFormats/Bgra4444.cs b/src/ImageSharp/PixelFormats/Bgra4444.cs index 90f967f898..f684bec339 100644 --- a/src/ImageSharp/PixelFormats/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/Bgra4444.cs @@ -178,6 +178,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Bgra5551.cs b/src/ImageSharp/PixelFormats/Bgra5551.cs index 3a18c03e83..1044a0febf 100644 --- a/src/ImageSharp/PixelFormats/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/Bgra5551.cs @@ -178,6 +178,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Byte4.cs b/src/ImageSharp/PixelFormats/Byte4.cs index bb1b350f07..aea3aec655 100644 --- a/src/ImageSharp/PixelFormats/Byte4.cs +++ b/src/ImageSharp/PixelFormats/Byte4.cs @@ -179,6 +179,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Gray16.cs b/src/ImageSharp/PixelFormats/Gray16.cs index a7e50e3667..6fda8b0817 100644 --- a/src/ImageSharp/PixelFormats/Gray16.cs +++ b/src/ImageSharp/PixelFormats/Gray16.cs @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Initializes a new instance of the struct. /// /// The gray component - public Gray16(byte gray) + public Gray16(ushort gray) { this.PackedValue = gray; } @@ -185,6 +185,34 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) + { + this.PackedValue = (ushort)(source.PackedValue * 255); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) + { + dest.PackedValue = (byte)(((this.PackedValue * 255) + 32895) >> 16); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) + { + this.PackedValue = source.PackedValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) + { + dest.PackedValue = this.PackedValue; + } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => @@ -252,9 +280,8 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] private static ushort Pack(float r, float g, float b) { - float sum = r + g + b; float val = (r * Rx) + (g * Gx) + (b * Bx); - return (ushort)Math.Round(val * 65535f / sum); // TODO: if this is correct, Rx, Gx, Bx consts could be scaled by 65535f directly! + return (ushort)Math.Round(val * 65535f); } /// diff --git a/src/ImageSharp/PixelFormats/Gray8.cs b/src/ImageSharp/PixelFormats/Gray8.cs index db05395431..1509f8ea9f 100644 --- a/src/ImageSharp/PixelFormats/Gray8.cs +++ b/src/ImageSharp/PixelFormats/Gray8.cs @@ -257,9 +257,8 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] private static byte Pack(float r, float g, float b) { - float sum = r + g + b; float val = (r * Rx) + (g * Gx) + (b * Bx); - return (byte)Math.Round(val * 255 / sum); // TODO: if this is correct, Rx, Gx, Bx consts could be scaled by 255 directly! + return (byte)Math.Round(val * 255); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/HalfSingle.cs b/src/ImageSharp/PixelFormats/HalfSingle.cs index 09b4636492..b392910a67 100644 --- a/src/ImageSharp/PixelFormats/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/HalfSingle.cs @@ -192,6 +192,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/HalfVector2.cs b/src/ImageSharp/PixelFormats/HalfVector2.cs index befa49736c..ac70f4fbcc 100644 --- a/src/ImageSharp/PixelFormats/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/HalfVector2.cs @@ -207,6 +207,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/HalfVector4.cs b/src/ImageSharp/PixelFormats/HalfVector4.cs index 885e022921..9bdae99abe 100644 --- a/src/ImageSharp/PixelFormats/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/HalfVector4.cs @@ -200,6 +200,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index ae09af626c..382c8541d6 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -126,5 +126,29 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The destination pixel to write to void ToBgra32(ref Bgra32 dest); + + /// + /// Packs the Pixel from an value. + /// + /// The value. + void PackFromGray8(Gray8 source); + + /// + /// Converts the pixel to format. + /// + /// The destination pixel to write to. + void ToGray8(ref Gray8 dest); + + /// + /// Packs the Pixel from an value. + /// + /// The value. + void PackFromGray16(Gray16 source); + + /// + /// Converts the pixel tgo value. + /// + /// The destination pixel to write to. + void ToGray16(ref Gray16 dest); } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/NormalizedByte2.cs index 8592fdd6a7..cd9fa65fbe 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte2.cs @@ -226,6 +226,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/NormalizedByte4.cs index 293d536e53..9b53adeccf 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte4.cs @@ -219,6 +219,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/NormalizedShort2.cs index 1ced412d06..3319a10927 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort2.cs @@ -213,6 +213,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/NormalizedShort4.cs index 25b26fa7f7..7a74a44349 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort4.cs @@ -221,6 +221,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)MathF.Round(vector.W); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Rg32.cs b/src/ImageSharp/PixelFormats/Rg32.cs index e5ceeacec2..e4bed1275b 100644 --- a/src/ImageSharp/PixelFormats/Rg32.cs +++ b/src/ImageSharp/PixelFormats/Rg32.cs @@ -191,6 +191,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Rgb24.cs b/src/ImageSharp/PixelFormats/Rgb24.cs index d7e1c47ec0..4c5aef5438 100644 --- a/src/ImageSharp/PixelFormats/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/Rgb24.cs @@ -166,6 +166,33 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = byte.MaxValue; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) + { + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) + { + var val = (byte)(((source.PackedValue * 255) + 32895) >> 16); + this.R = val; + this.G = val; + this.B = val; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) diff --git a/src/ImageSharp/PixelFormats/Rgb48.cs b/src/ImageSharp/PixelFormats/Rgb48.cs index 2d92b0e4e3..7784c49ffb 100644 --- a/src/ImageSharp/PixelFormats/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/Rgb48.cs @@ -210,6 +210,39 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) + { + var val = (ushort)(source.PackedValue * 255); + this.R = val; + this.G = val; + this.B = val; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) + { + dest.PackFromRgb48(this); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) + { + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) + { + dest.PackFromRgb48(this); + } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this = source; diff --git a/src/ImageSharp/PixelFormats/Rgba1010102.cs b/src/ImageSharp/PixelFormats/Rgba1010102.cs index 94fb7a41e6..6dd5f7b544 100644 --- a/src/ImageSharp/PixelFormats/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/Rgba1010102.cs @@ -185,6 +185,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)MathF.Round(vector.W); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index cf66538c52..aab9fad928 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -336,6 +336,41 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = this.A; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) + { + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + this.A = 0; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) + { + dest.PackFromRgba32(this); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) + { + var val = (byte)(((source.PackedValue * 255) + 32895) >> 16); + this.R = val; + this.G = val; + this.B = val; + this.A = 0; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) + { + dest.PackFromRgba32(this); + } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromScaledVector4(Vector4 vector) diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/Rgba64.cs index 8e6be1e8c4..5c3187856e 100644 --- a/src/ImageSharp/PixelFormats/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/Rgba64.cs @@ -274,6 +274,35 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)(((this.A * 255) + 32895) >> 16); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) + { + ushort x = (ushort)(source.PackedValue * 255); + this.R = x; + this.G = x; + this.B = x; + this.A = ushort.MaxValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) + { + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + this.A = ushort.MaxValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// public override bool Equals(object obj) { diff --git a/src/ImageSharp/PixelFormats/RgbaVector.cs b/src/ImageSharp/PixelFormats/RgbaVector.cs index dd5f77b80f..3ab45a66ef 100644 --- a/src/ImageSharp/PixelFormats/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/RgbaVector.cs @@ -298,6 +298,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)MathF.Round(vector.W); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Short2.cs b/src/ImageSharp/PixelFormats/Short2.cs index 9fc7618b91..331c5fb208 100644 --- a/src/ImageSharp/PixelFormats/Short2.cs +++ b/src/ImageSharp/PixelFormats/Short2.cs @@ -207,6 +207,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Short4.cs b/src/ImageSharp/PixelFormats/Short4.cs index 641f154f94..4a3d89ad8b 100644 --- a/src/ImageSharp/PixelFormats/Short4.cs +++ b/src/ImageSharp/PixelFormats/Short4.cs @@ -213,6 +213,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)MathF.Round(vector.W); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromVector4(this.ToVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromVector4(this.ToVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs new file mode 100644 index 0000000000..2525ee3796 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs @@ -0,0 +1,211 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.PixelFormats +{ + public class Gray16Tests + { + [Theory] + [InlineData(0)] + [InlineData(65535)] + [InlineData(32767)] + [InlineData(42)] + public void Gray16_PackedValue_EqualsInput(ushort input) + { + Assert.Equal(input, new Gray16(input).PackedValue); + } + + [Theory] + [InlineData(0)] + [InlineData(65535)] + [InlineData(32767)] + public void Gray16_ToVector4(ushort input) + { + // arrange + var gray = new Gray16(input); + + // act + var actual = gray.ToVector4(); + + // assert + Assert.Equal(input, actual.X); + Assert.Equal(input, actual.Y); + Assert.Equal(input, actual.Z); + Assert.Equal(1, actual.W); + } + + [Theory] + [InlineData(0)] + [InlineData(65535)] + [InlineData(32767)] + public void Gray16_ToScaledVector4(ushort input) + { + // arrange + var gray = new Gray16(input); + + // act + var actual = gray.ToScaledVector4(); + + // assert + float scaledInput = input / 65535f; + Assert.Equal(scaledInput, actual.X); + Assert.Equal(scaledInput, actual.Y); + Assert.Equal(scaledInput, actual.Z); + Assert.Equal(1, actual.W); + } + + [Fact] + public void Gray16_PackFromScaledVector4() + { + // arrange + Gray16 gray = default; + int expected = 32767; + Vector4 scaled = new Gray16((ushort)expected).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + ushort actual = gray.PackedValue; + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray16_PackFromScaledVector4_ToRgb24() + { + // arrange + Rgb24 actual = default; + Gray16 gray = default; + var expected = new Rgb24(128, 128, 128); + Vector4 scaled = new Gray16(32768).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToRgb24(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray16_PackFromScaledVector4_ToRgba32() + { + // arrange + Rgba32 actual = default; + Gray16 gray = default; + var expected = new Rgba32(128, 128, 128, 255); + Vector4 scaled = new Gray16(32768).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToRgba32(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray16_PackFromScaledVector4_ToBgr24() + { + // arrange + Bgr24 actual = default; + Gray16 gray = default; + var expected = new Bgr24(128, 128, 128); + Vector4 scaled = new Gray16(32768).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToBgr24(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray16_PackFromScaledVector4_ToBgra32() + { + // arrange + Bgra32 actual = default; + Gray16 gray = default; + var expected = new Bgra32(128,128,128); + Vector4 scaled = new Gray16(32768).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToBgra32(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray16_PackFromScaledVector4_ToArgb32() + { + // arrange + Gray16 gray = default; + Argb32 actual = default; + var expected = new Argb32(128, 128, 128); + Vector4 scaled = new Gray16(32768).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToArgb32(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray16_PackFromScaledVector4_ToRgba64() + { + // arrange + Gray16 gray = default; + Rgba64 actual = default; + var expected = new Rgba64(65535, 65535, 65535, 65535); + Vector4 scaled = new Gray16(65535).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToRgba64(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray16_PackFromRgb48_ToRgb48() + { + // arrange + var gray = default(Gray16); + var actual = default(Rgb48); + var expected = new Rgb48(0, 0, 0); + + // act + gray.PackFromRgb48(expected); + gray.ToRgb48(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray16_PackFromRgba64_ToRgba64() + { + // arrange + var gray = default(Gray16); + var actual = default(Rgba64); + var expected = new Rgba64(0, 0, 0, 65535); + + // act + gray.PackFromRgba64(expected); + gray.ToRgba64(ref actual); + + // assert + Assert.Equal(expected, actual); + } + } +} From 5d35bcddcc2b435009ad7e1eaf26b760d601ad0a Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sat, 6 Oct 2018 23:55:34 +0200 Subject: [PATCH 113/381] #718: add missing inheritdoc comments --- src/ImageSharp/PixelFormats/Gray8.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ImageSharp/PixelFormats/Gray8.cs b/src/ImageSharp/PixelFormats/Gray8.cs index 1509f8ea9f..916e199d07 100644 --- a/src/ImageSharp/PixelFormats/Gray8.cs +++ b/src/ImageSharp/PixelFormats/Gray8.cs @@ -195,9 +195,11 @@ namespace SixLabors.ImageSharp.PixelFormats public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromGray8(Gray8 source) => this.PackedValue = source.PackedValue; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromGray16(Gray16 source) => this.PackedValue = (byte)(source.PackedValue / 255); From c8efad0d15f2a2de2304f382075f3d48f620c9f8 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 7 Oct 2018 00:08:42 +0200 Subject: [PATCH 114/381] #718: add missing documentation --- src/ImageSharp/PixelFormats/Gray16.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/PixelFormats/Gray16.cs b/src/ImageSharp/PixelFormats/Gray16.cs index 6fda8b0817..06da2867a9 100644 --- a/src/ImageSharp/PixelFormats/Gray16.cs +++ b/src/ImageSharp/PixelFormats/Gray16.cs @@ -287,7 +287,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Packs the into a byte. /// - /// + /// The . [MethodImpl(MethodImplOptions.AggressiveInlining)] private byte PackedAsByte() { From 99b114a7e5d0d51b45728eb654d10efadaf250ed Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 00:09:41 +0200 Subject: [PATCH 115/381] 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 a67386977cd24dc38264ecad8cd774bb37c21f20 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 6 Oct 2018 23:10:52 +0100 Subject: [PATCH 116/381] 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 7effe7238bf6e7d9d8dd7b2d62ba3f09171b14ab Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 00:19:26 +0200 Subject: [PATCH 117/381] 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 81313d07f7d77461a60d3c4b1931b66ad329dc19 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 00:36:45 +0200 Subject: [PATCH 118/381] 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 e8eb6a72b6391988cf4ca3d0ce841320a835a907 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 00:55:10 +0200 Subject: [PATCH 119/381] 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 b5ef7d9bfb6b212bd2645b13bf84da71b1988b1b Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 01:25:53 +0200 Subject: [PATCH 120/381] 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 c1afe359db855fb6fb9c0887aceece0dcd44e5d2 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 01:41:26 +0200 Subject: [PATCH 121/381] 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 30a26d52f8d2ee9e9fffbc718404c11af0902270 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 02:07:15 +0200 Subject: [PATCH 122/381] 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 d0afcc8b156cdf248d692b26cd1043e6678b9d57 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 02:52:11 +0200 Subject: [PATCH 123/381] 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 e7bb01b62b01c2dbceb7d6d40f90ef67de42c0e1 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 11:08:47 +0200 Subject: [PATCH 124/381] 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 78e598cad3ba528aeffcb531d5265af3b16437eb Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 12:02:17 +0200 Subject: [PATCH 125/381] 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 ce0a17f589889d1c14197097e3ff24635d011d2e Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 20:17:59 +0200 Subject: [PATCH 126/381] 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 e907ec95613de55527db11cb5797922aeb01b409 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 20:32:47 +0200 Subject: [PATCH 127/381] 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 44004ccff70da7723c7a16314387aa0351890cd8 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 20:46:31 +0200 Subject: [PATCH 128/381] 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 0c437c35a698a7f35b9e656fd3fd5f2a20252505 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 21:35:23 +0200 Subject: [PATCH 129/381] 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 12f4b9675f221c5de5bdde5553a4e5c8cf7d6587 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 21:50:58 +0200 Subject: [PATCH 130/381] 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 17ae98d5b2d2590a6ab47bccec85e1ff6c753f51 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 7 Oct 2018 22:16:44 +0100 Subject: [PATCH 131/381] 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 1533c4cbcb32f331ce3ca6af526c7998ae96c4b5 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 8 Oct 2018 19:00:01 +0100 Subject: [PATCH 132/381] Fix Gray8 --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 67 +++++++ src/ImageSharp/PixelFormats/Alpha8.cs | 105 +++-------- src/ImageSharp/PixelFormats/Gray8.cs | 188 +++++++++----------- 3 files changed, 176 insertions(+), 184 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index c15e0a7329..f9ade4cfe3 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -13,6 +13,73 @@ namespace SixLabors.ImageSharp /// internal static class ImageMaths { + /// + /// Gets the luminance from the rgb components using the formula as specified by ITU-R Recommendation BT.709. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static byte GetBT709LuminanceBytes(byte r, byte g, byte b) => (byte)((r * .2126F) + (g * .7152F) + (b * .0722F)); + + /// + /// Gets the luminance from the rgb components using the formula as specified by ITU-R Recommendation BT.709. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static ushort GetBT709Luminance(ushort r, ushort g, ushort b) => (ushort)((r * .2126F) + (g * .7152F) + (b * .0722F)); + + /// + /// Scales a value from a 16 bit to it's 8 bit equivalent. + /// + /// The 8 bit compoonent value. + /// The + [MethodImpl(InliningOptions.ShortMethod)] + public static byte DownScaleFrom16BitTo8Bit(ushort component) + { + // To scale to 8 bits From a 16-bit value V the required value (from the PNG specification) is: + // + // (V * 255) / 65535 + // + // This reduces to round(V / 257), or floor((V + 128.5)/257) + // + // Represent V as the two byte value vhi.vlo. Make a guess that the + // result is the top byte of V, vhi, then the correction to this value + // is: + // + // error = floor(((V-vhi.vhi) + 128.5) / 257) + // = floor(((vlo-vhi) + 128.5) / 257) + // + // This can be approximated using integer arithmetic (and a signed + // shift): + // + // error = (vlo-vhi+128) >> 8; + // + // The approximate differs from the exact answer only when (vlo-vhi) is + // 128; it then gives a correction of +1 when the exact correction is + // 0. This gives 128 errors. The exact answer (correct for all 16-bit + // input values) is: + // + // error = (vlo-vhi+128)*65535 >> 24; + // + // An alternative arithmetic calculation which also gives no errors is: + // + // (V * 255 + 32895) >> 16 + return (byte)(((component * 255) + 32895) >> 16); + } + + /// + /// Scales a value from an 8 bit to it's 16 bit equivalent. + /// + /// The 8 bit compoonent value. + /// The + [MethodImpl(InliningOptions.ShortMethod)] + public static ushort UpscaleFrom8BitTo16Bit(byte component) => (ushort)(component * 257); + /// /// Returns the absolute value of a 32-bit signed integer. Uses bit shifting to speed up the operation. /// diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/Alpha8.cs index d795931af3..177ce81efd 100644 --- a/src/ImageSharp/PixelFormats/Alpha8.cs +++ b/src/ImageSharp/PixelFormats/Alpha8.cs @@ -19,10 +19,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Initializes a new instance of the struct. /// /// The alpha component - public Alpha8(float alpha) - { - this.PackedValue = Pack(alpha); - } + public Alpha8(float alpha) => this.PackedValue = Pack(alpha); /// public byte PackedValue { get; set; } @@ -40,10 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// True if the parameter is equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Alpha8 left, Alpha8 right) - { - return left.PackedValue == right.PackedValue; - } + public static bool operator ==(Alpha8 left, Alpha8 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -54,77 +48,48 @@ namespace SixLabors.ImageSharp.PixelFormats /// True if the parameter is not equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Alpha8 left, Alpha8 right) - { - return left.PackedValue != right.PackedValue; - } + public static bool operator !=(Alpha8 left, Alpha8 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [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.PackedValue = Pack(vector.W); - } + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(vector.W); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(0, 0, 0, this.PackedValue / 255F); - } + public Vector4 ToVector4() => new Vector4(0, 0, 0, this.PackedValue / 255F); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackedValue = source.A; - } + public void PackFromRgba32(Rgba32 source) => this.PackedValue = source.A; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackedValue = source.A; - } + public void PackFromArgb32(Argb32 source) => this.PackedValue = source.A; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackedValue = source.A; - } + public void PackFromBgra32(Bgra32 source) => this.PackedValue = source.A; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest = default(Rgb24); - } + public void ToRgb24(ref Rgb24 dest) => dest = default; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ToRgba32(ref Rgba32 dest) { - dest.R = 0; - dest.G = 0; - dest.B = 0; + dest.Rgb = default; dest.A = this.PackedValue; } @@ -140,10 +105,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - dest = default(Bgr24); - } + public void ToBgr24(ref Bgr24 dest) => dest = default; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -161,28 +123,23 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) - { - dest.R = 0; - dest.G = 0; - dest.B = 0; - } + public void ToRgb48(ref Rgb48 dest) => dest = default; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromGray8(Gray8 source) => this.PackedValue = 255; + public void PackFromGray8(Gray8 source) => this.PackedValue = byte.MaxValue; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackedValue = 0; + public void ToGray8(ref Gray8 dest) => dest = default; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromGray16(Gray16 source) => this.PackedValue = 255; + public void PackFromGray16(Gray16 source) => this.PackedValue = byte.MaxValue; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackedValue = 0; + public void ToGray16(ref Gray16 dest) => dest = default; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -190,17 +147,18 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) + { + dest.Rgb = default; + dest.A = ImageMaths.UpscaleFrom8BitTo16Bit(this.PackedValue); + } /// /// Compares an object with the packed vector. /// /// The object to compare. /// True if the object is equal to the packed vector. - public override bool Equals(object obj) - { - return obj is Alpha8 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Alpha8 other && this.Equals(other); /// /// Compares another Alpha8 packed vector with the packed vector. @@ -208,19 +166,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// The Alpha8 packed vector to compare. /// True if the packed vectors are equal. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Alpha8 other) - { - return this.PackedValue == other.PackedValue; - } + public bool Equals(Alpha8 other) => this.PackedValue.Equals(other.PackedValue); /// /// Gets a string representation of the packed vector. /// /// A string representation of the packed vector. - public override string ToString() - { - return (this.PackedValue / 255F).ToString(); - } + public override string ToString() => (this.PackedValue / 255F).ToString(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -232,9 +184,6 @@ namespace SixLabors.ImageSharp.PixelFormats /// The float containing the value to pack. /// The containing the packed values. [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static byte Pack(float alpha) - { - return (byte)Math.Round(alpha.Clamp(0, 1) * 255F); - } + private static byte Pack(float alpha) => (byte)Math.Round(alpha.Clamp(0, 1) * 255F); } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Gray8.cs b/src/ImageSharp/PixelFormats/Gray8.cs index 916e199d07..0a41a6ecc6 100644 --- a/src/ImageSharp/PixelFormats/Gray8.cs +++ b/src/ImageSharp/PixelFormats/Gray8.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; @@ -30,14 +29,21 @@ namespace SixLabors.ImageSharp.PixelFormats /// private const float Bx = .0722F; + /// + /// The maximum byte value. + /// + private static readonly Vector4 MaxBytes = new Vector4(255F); + + /// + /// The half vector value. + /// + private static readonly Vector4 Half = new Vector4(0.5F); + /// /// Initializes a new instance of the struct. /// /// The gray component - public Gray8(byte gray) - { - this.PackedValue = gray; - } + public Gray8(byte gray) => this.PackedValue = gray; /// public byte PackedValue { get; set; } @@ -45,20 +51,13 @@ 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. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Gray8 left, Gray8 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Gray8 left, Gray8 right) => left.PackedValue.Equals(right.PackedValue); /// /// Compares two objects for equality. @@ -68,67 +67,54 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Gray8 left, Gray8 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Gray8 left, Gray8 right) => !left.PackedValue.Equals(right.PackedValue); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - var scaledGray = this.PackedValue / 255f; - return new Vector4(scaledGray, scaledGray, scaledGray, 1.0f); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z); + vector *= MaxBytes; + vector += Half; + vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + float luminance = (vector.X * Rx) + (vector.Y * Gx) + (vector.Z * Bx); + + this.PackedValue = (byte)luminance; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { - return new Vector4(this.PackedValue, this.PackedValue, this.PackedValue, 1.0f); + float rgb = this.PackedValue / 255F; + return new Vector4(rgb, rgb, rgb, 1F); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackedValue = Pack(source.R, source.G, source.B); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackedValue = ImageMaths.GetBT709LuminanceBytes(source.R, source.G, source.B); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackedValue = Pack(source.R, source.G, source.B); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackedValue = ImageMaths.GetBT709LuminanceBytes(source.R, source.G, source.B); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackedValue = Pack(source.R, source.G, source.B); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackedValue = ImageMaths.GetBT709LuminanceBytes(source.R, source.G, source.B); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void ToRgb24(ref Rgb24 dest) { dest.R = this.PackedValue; @@ -137,27 +123,27 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { dest.R = this.PackedValue; dest.G = this.PackedValue; dest.B = this.PackedValue; - dest.A = 255; + dest.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void ToArgb32(ref Argb32 dest) { dest.R = this.PackedValue; dest.G = this.PackedValue; dest.B = this.PackedValue; - dest.A = 255; + dest.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void ToBgr24(ref Bgr24 dest) { dest.R = this.PackedValue; @@ -166,101 +152,91 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void ToBgra32(ref Bgra32 dest) { dest.R = this.PackedValue; dest.G = this.PackedValue; dest.B = this.PackedValue; - dest.A = 255; + dest.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => - this.PackedValue = Pack(source.R, source.G, source.B); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) + => this.PackedValue = ImageMaths.GetBT709LuminanceBytes( + ImageMaths.DownScaleFrom16BitTo8Bit(source.R), + ImageMaths.DownScaleFrom16BitTo8Bit(source.G), + ImageMaths.DownScaleFrom16BitTo8Bit(source.B)); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void ToRgb48(ref Rgb48 dest) { - ushort gray = (ushort)(this.PackedValue * 255); - dest.R = gray; - dest.G = gray; - dest.B = gray; + ushort luminance = ImageMaths.UpscaleFrom8BitTo16Bit(this.PackedValue); + dest.R = luminance; + dest.G = luminance; + dest.B = luminance; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => - this.PackFromScaledVector4(source.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba64(Rgba64 source) + => this.PackedValue = ImageMaths.GetBT709LuminanceBytes( + ImageMaths.DownScaleFrom16BitTo8Bit(source.R), + ImageMaths.DownScaleFrom16BitTo8Bit(source.G), + ImageMaths.DownScaleFrom16BitTo8Bit(source.B)); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackedValue = source.PackedValue; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromGray16(Gray16 source) => this.PackedValue = (byte)(source.PackedValue / 255); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackedValue = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba64(ref Rgba64 dest) + { + ushort luminance = ImageMaths.UpscaleFrom8BitTo16Bit(this.PackedValue); + dest.R = luminance; + dest.G = luminance; + dest.B = luminance; + dest.A = ushort.MaxValue; + } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void ToGray8(ref Gray8 dest) => dest.PackedValue = this.PackedValue; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackedValue = (ushort)(this.PackedValue * 255); + [MethodImpl(InliningOptions.ShortMethod)] + public void ToGray16(ref Gray16 dest) => dest.PackedValue = ImageMaths.UpscaleFrom8BitTo16Bit(this.PackedValue); /// /// Compares an object with the packed vector. /// /// The object to compare. /// True if the object is equal to the packed vector. - public override bool Equals(object obj) - { - return obj is Gray8 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Gray8 other && this.Equals(other); /// /// Compares another packed vector with the packed vector. /// /// The Gray8 packed vector to compare. /// True if the packed vectors are equal. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Gray8 other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Gray8 other) => this.PackedValue.Equals(other.PackedValue); /// /// Gets a string representation of the packed vector. /// /// A string representation of the packed vector. - public override string ToString() - { - return (this.PackedValue / 255F).ToString(); - } + public override string ToString() => $"Gray8({this.PackedValue}"; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - - /// - /// Packs a into a byte. - /// - /// Red value of the color to pack. - /// Green value of the color to pack. - /// Blue value of the color to pack. - /// The containing the packed value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static byte Pack(float r, float g, float b) - { - float val = (r * Rx) + (g * Gx) + (b * Bx); - return (byte)Math.Round(val * 255); - } } } \ No newline at end of file From 295021928737eb149b949b39cd8dc77e7581e238 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 9 Oct 2018 23:57:23 +0100 Subject: [PATCH 133/381] Update and normalise pixel format + disable out of date tests --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 4 +- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 4 +- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 34 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 116 +- src/ImageSharp/PixelFormats/Alpha8.cs | 102 +- src/ImageSharp/PixelFormats/Argb32.cs | 260 +--- src/ImageSharp/PixelFormats/Bgr24.cs | 191 +-- src/ImageSharp/PixelFormats/Bgr565.cs | 216 +-- src/ImageSharp/PixelFormats/Bgra32.cs | 230 +-- src/ImageSharp/PixelFormats/Bgra4444.cs | 200 +-- src/ImageSharp/PixelFormats/Bgra5551.cs | 209 +-- src/ImageSharp/PixelFormats/Byte4.cs | 182 +-- .../PixelOperations{TPixel}.Generated.cs | 113 +- .../PixelOperations{TPixel}.Generated.tt | 8 +- .../Rgba32.PixelOperations.Generated.cs | 12 +- .../Rgba32.PixelOperations.Generated.tt | 12 +- src/ImageSharp/PixelFormats/Gray16.cs | 262 +--- src/ImageSharp/PixelFormats/Gray8.cs | 136 +- src/ImageSharp/PixelFormats/HalfSingle.cs | 200 +-- src/ImageSharp/PixelFormats/HalfTypeHelper.cs | 12 +- src/ImageSharp/PixelFormats/HalfVector2.cs | 231 +-- src/ImageSharp/PixelFormats/HalfVector4.cs | 203 +-- src/ImageSharp/PixelFormats/IPixel.cs | 96 +- .../PixelFormats/NormalizedByte2.cs | 263 +--- .../PixelFormats/NormalizedByte4.cs | 244 +-- .../PixelFormats/NormalizedShort2.cs | 253 +-- .../PixelFormats/NormalizedShort4.cs | 257 +--- src/ImageSharp/PixelFormats/Rg32.cs | 230 +-- src/ImageSharp/PixelFormats/Rgb24.cs | 185 +-- src/ImageSharp/PixelFormats/Rgb48.cs | 206 +-- src/ImageSharp/PixelFormats/Rgba1010102.cs | 222 +-- src/ImageSharp/PixelFormats/Rgba32.cs | 306 +--- src/ImageSharp/PixelFormats/Rgba64.cs | 248 +-- src/ImageSharp/PixelFormats/RgbaVector.cs | 355 +---- src/ImageSharp/PixelFormats/Short2.cs | 250 +-- src/ImageSharp/PixelFormats/Short4.cs | 248 +-- .../BinaryErrorDiffusionProcessor.cs | 11 +- .../BinaryOrderedDitherProcessor.cs | 9 +- .../Binarization/BinaryThresholdProcessor.cs | 9 +- .../ErrorDiffusionPaletteProcessor.cs | 12 +- .../OrderedDitherPaletteProcessor.cs | 15 +- .../OctreeFrameQuantizer{TPixel}.cs | 49 +- .../Quantization/WuFrameQuantizer{TPixel}.cs | 48 +- .../ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs | 32 +- .../Color/Bulk/ToXyzw.cs | 14 +- .../ImageSharp.Tests/ImageSharp.Tests.csproj | 8 +- tests/ImageSharp.Tests/Issues/Issue594.cs | 174 +-- .../PixelFormats/Alpha8Tests.cs | 266 ++-- .../PixelFormats/Argb32Tests.cs | 308 ++-- .../PixelFormats/Bgr24Tests.cs | 150 +- .../PixelFormats/Bgr565Tests.cs | 212 +-- .../PixelFormats/Bgra32Tests.cs | 150 +- .../PixelFormats/Bgra4444Tests.cs | 308 ++-- .../PixelFormats/Bgra5551Tests.cs | 308 ++-- .../PixelFormats/Byte4Tests.cs | 308 ++-- .../PixelFormats/ColorConstructorTests.cs | 151 -- .../PixelFormats/ColorEqualityTests.cs | 216 --- .../PixelFormats/ColorPackingTests.cs | 88 -- .../PixelFormats/Gray16Tests.cs | 376 ++--- .../PixelFormats/Gray8Tests.cs | 302 ++-- .../PixelFormats/HalfSingleTests.cs | 212 +-- .../PixelFormats/HalfVector2Tests.cs | 212 +-- .../PixelFormats/HalfVector4Tests.cs | 308 ++-- .../PixelFormats/NormalizedByte2Tests.cs | 244 +-- .../PixelFormats/NormalizedByte4Tests.cs | 278 ++-- .../PixelFormats/NormalizedShort2Tests.cs | 246 +-- .../PixelFormats/NormalizedShort4Tests.cs | 278 ++-- .../PixelFormats/PixelOperationsTests.cs | 1354 ++++++++--------- .../PixelFormats/Rg32Tests.cs | 182 +-- .../PixelFormats/Rgb24Tests.cs | 350 ++--- .../PixelFormats/Rgb48Tests.cs | 391 +++-- .../PixelFormats/Rgba1010102Tests.cs | 278 ++-- .../PixelFormats/Rgba32Tests.cs | 110 +- .../PixelFormats/Rgba64Tests.cs | 221 +-- .../PixelFormats/RgbaVectorTests.cs | 50 +- .../PixelFormats/Short2Tests.cs | 74 +- .../PixelFormats/Short4Tests.cs | 74 +- .../PixelFormats/UnPackedPixelTests.cs | 64 +- .../Transforms/AffineTransformTests.cs | 13 +- .../Quantization/QuantizedImageTests.cs | 5 +- .../TestUtilities/ImagingTestCaseUtility.cs | 12 +- .../TestUtilities/TestUtils.cs | 16 +- .../Tests/TestImageProviderTests.cs | 38 +- 83 files changed, 5479 insertions(+), 9355 deletions(-) delete mode 100644 tests/ImageSharp.Tests/PixelFormats/ColorConstructorTests.cs delete mode 100644 tests/ImageSharp.Tests/PixelFormats/ColorEqualityTests.cs delete mode 100644 tests/ImageSharp.Tests/PixelFormats/ColorPackingTests.cs diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index f9ade4cfe3..7bf73245f7 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp /// The blue component. /// The . [MethodImpl(InliningOptions.ShortMethod)] - public static byte GetBT709LuminanceBytes(byte r, byte g, byte b) => (byte)((r * .2126F) + (g * .7152F) + (b * .0722F)); + public static byte Get8BitBT709Luminance(byte r, byte g, byte b) => (byte)((r * .2126F) + (g * .7152F) + (b * .0722F)); /// /// Gets the luminance from the rgb components using the formula as specified by ITU-R Recommendation BT.709. @@ -31,7 +31,7 @@ namespace SixLabors.ImageSharp /// The blue component. /// The . [MethodImpl(InliningOptions.ShortMethod)] - public static ushort GetBT709Luminance(ushort r, ushort g, ushort b) => (ushort)((r * .2126F) + (g * .7152F) + (b * .0722F)); + public static ushort Get16BitBT709Luminance(ushort r, ushort g, ushort b) => (ushort)((r * .2126F) + (g * .7152F) + (b * .0722F)); /// /// Scales a value from a 16 bit to it's 8 bit equivalent. diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 44e42528cf..186ff812f7 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -101,9 +101,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp var fileHeader = new BmpFileHeader( type: 19778, // BM - offset: 54, + fileSize: 54 + infoHeader.ImageSize, reserved: 0, - fileSize: 54 + infoHeader.ImageSize); + offset: 54); #if NETCOREAPP2_1 Span buffer = stackalloc byte[40]; diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index ae0366e6e6..f00a6b61e3 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -210,16 +211,20 @@ namespace SixLabors.ImageSharp.Formats.Gif { // Transparent pixels are much more likely to be found at the end of a palette int index = -1; - Rgba32 trans = default; + int length = quantized.Palette.Length; - ref TPixel paletteRef = ref MemoryMarshal.GetReference(quantized.Palette.AsSpan()); - for (int i = quantized.Palette.Length - 1; i >= 0; i--) + using (IMemoryOwner rgbaBuffer = this.memoryAllocator.Allocate(length)) { - ref TPixel entry = ref Unsafe.Add(ref paletteRef, i); - entry.ToRgba32(ref trans); - if (trans.Equals(default)) + Span rgbaSpan = rgbaBuffer.GetSpan(); + ref Rgba32 paletteRef = ref MemoryMarshal.GetReference(rgbaSpan); + PixelOperations.Instance.ToRgba32(quantized.Palette, rgbaSpan, length); + + for (int i = quantized.Palette.Length - 1; i >= 0; i--) { - index = i; + if (Unsafe.Add(ref paletteRef, i).Equals(default)) + { + index = i; + } } } @@ -406,24 +411,13 @@ namespace SixLabors.ImageSharp.Formats.Gif private void WriteColorTable(QuantizedFrame image, Stream stream) where TPixel : struct, IPixel { - int pixelCount = image.Palette.Length; - // The maximium number of colors for the bit depth int colorTableLength = ImageMaths.GetColorCountForBitDepth(this.bitDepth) * 3; - Rgb24 rgb = default; + int pixelCount = image.Palette.Length; using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength)) { - ref TPixel paletteRef = ref MemoryMarshal.GetReference(image.Palette.AsSpan()); - ref Rgb24 rgb24Ref = ref Unsafe.As(ref MemoryMarshal.GetReference(colorTable.GetSpan())); - for (int i = 0; i < pixelCount; i++) - { - ref TPixel entry = ref Unsafe.Add(ref paletteRef, i); - entry.ToRgb24(ref rgb); - Unsafe.Add(ref rgb24Ref, i) = rgb; - } - - // Write the palette to the stream + PixelOperations.Instance.ToRgb24Bytes(image.Palette.AsSpan(), colorTable.GetSpan(), pixelCount); stream.Write(colorTable.Array, 0, colorTableLength); } } diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index a46d83707e..1e9dbc71a1 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Buffers.Binary; using System.Collections.Generic; using System.IO; @@ -312,11 +313,6 @@ namespace SixLabors.ImageSharp.Formats.Png private void CollectGrayscaleBytes(ReadOnlySpan rowSpan) where TPixel : struct, IPixel { - // Use ITU-R recommendation 709 to match libpng. - const float RX = .2126F; - const float GX = .7152F; - const float BX = .0722F; - ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); Span rawScanlineSpan = this.rawScanline.GetSpan(); ref byte rawScanlineSpanRef = ref MemoryMarshal.GetReference(rawScanlineSpan); @@ -327,12 +323,18 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.use16Bit) { // 16 bit grayscale - Rgb48 rgb = default; - for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 2) + using (IMemoryOwner luminanceBuffer = this.memoryAllocator.Allocate(rowSpan.Length)) { - 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); + Span luminanceSpan = luminanceBuffer.GetSpan(); + ref Gray16 luminanceRef = ref MemoryMarshal.GetReference(luminanceSpan); + PixelOperations.Instance.ToGray16(rowSpan, luminanceSpan, rowSpan.Length); + + // Can't map directly to byte array as it's big endian. + for (int x = 0, o = 0; x < luminanceSpan.Length; x++, o += 2) + { + Gray16 luminance = Unsafe.Add(ref luminanceRef, x); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance.PackedValue); + } } } else @@ -340,12 +342,7 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.bitDepth == 8) { // 8 bit grayscale - Rgb24 rgb = default; - for (int x = 0; x < rowSpan.Length; x++) - { - Unsafe.Add(ref rowSpanRef, x).ToRgb24(ref rgb); - Unsafe.Add(ref rawScanlineSpanRef, x) = (byte)((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)); - } + PixelOperations.Instance.ToGray8Bytes(rowSpan, rawScanlineSpan, rowSpan.Length); } else { @@ -356,14 +353,9 @@ namespace SixLabors.ImageSharp.Formats.Png Span tempSpan = temp.GetSpan(); ref byte tempSpanRef = ref MemoryMarshal.GetReference(tempSpan); - Rgb24 rgb = default; - for (int x = 0; x < rowSpan.Length; x++) - { - Unsafe.Add(ref rowSpanRef, x).ToRgb24(ref rgb); - float luminance = ((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)) / scaleFactor; - Unsafe.Add(ref tempSpanRef, x) = (byte)luminance; - this.ScaleDownFrom8BitArray(tempSpan, rawScanlineSpan, this.bitDepth); - } + // We need to first create an array of luminance bytes then scale them down to the correct bit depth. + PixelOperations.Instance.ToGray8Bytes(rowSpan, tempSpan, rowSpan.Length); + this.ScaleDownFrom8BitArray(tempSpan, rawScanlineSpan, this.bitDepth, scaleFactor); } } } @@ -373,23 +365,31 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.use16Bit) { // 16 bit grayscale + alpha - Rgba64 rgba = default; - for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 4) + // TODO: Should we consider in the future a GrayAlpha32 type. + using (IMemoryOwner rgbaBuffer = this.memoryAllocator.Allocate(rowSpan.Length)) { - 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); + Span rgbaSpan = rgbaBuffer.GetSpan(); + ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan); + PixelOperations.Instance.ToRgba64(rowSpan, rgbaSpan, rowSpan.Length); + + // Can't map directly to byte array as it's big endian. + for (int x = 0, o = 0; x < rgbaSpan.Length; x++, o += 4) + { + Rgba64 rgba = Unsafe.Add(ref rgbaRef, x); + ushort luminance = ImageMaths.Get16BitBT709Luminance(rgba.R, rgba.G, rgba.B); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.A); + } } } else { // 8 bit grayscale + alpha - Rgba32 rgba = default; + // TODO: Should we consider in the future a GrayAlpha16 type. for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 2) { - Unsafe.Add(ref rowSpanRef, x).ToRgba32(ref rgba); - Unsafe.Add(ref rawScanlineSpanRef, o) = (byte)((RX * rgba.R) + (GX * rgba.G) + (BX * rgba.B)); + var rgba = Unsafe.Add(ref rowSpanRef, x).ToRgba32(); + Unsafe.Add(ref rawScanlineSpanRef, o) = ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); Unsafe.Add(ref rawScanlineSpanRef, o + 1) = rgba.A; } } @@ -425,15 +425,21 @@ namespace SixLabors.ImageSharp.Formats.Png case 8: { // 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) + using (IMemoryOwner rgbaBuffer = this.memoryAllocator.Allocate(rowSpan.Length)) { - 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); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 6, 2), rgba.A); + Span rgbaSpan = rgbaBuffer.GetSpan(); + ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan); + PixelOperations.Instance.ToRgba64(rowSpan, rgbaSpan, rowSpan.Length); + + // Can't map directly to byte array as it's big endian. + for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 8) + { + Rgba64 rgba = Unsafe.Add(ref rgbaRef, x); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgba.R); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.G); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgba.B); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 6, 2), rgba.A); + } } break; @@ -442,14 +448,20 @@ namespace SixLabors.ImageSharp.Formats.Png default: { // 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) + using (IMemoryOwner rgbBuffer = this.memoryAllocator.Allocate(rowSpan.Length)) { - 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); + Span rgbSpan = rgbBuffer.GetSpan(); + ref Rgb48 rgbRef = ref MemoryMarshal.GetReference(rgbSpan); + PixelOperations.Instance.ToRgb48(rowSpan, rgbSpan, rowSpan.Length); + + // Can't map directly to byte array as it's big endian. + for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 6) + { + Rgb48 rgb = Unsafe.Add(ref rgbRef, x); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgb.R); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgb.G); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgb.B); + } } break; @@ -624,7 +636,6 @@ namespace SixLabors.ImageSharp.Formats.Png TPixel[] palette = quantized.Palette; int paletteLength = Math.Min(palette.Length, 256); int colorTableLength = paletteLength * 3; - Rgba32 rgba = default; bool anyAlpha = false; using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength)) @@ -639,7 +650,7 @@ namespace SixLabors.ImageSharp.Formats.Png if (quantizedSpan.IndexOf((byte)i) > -1) { int offset = i * 3; - palette[i].ToRgba32(ref rgba); + var rgba = palette[i].ToRgba32(); byte alpha = rgba.A; @@ -851,7 +862,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// The source span in 8 bits. /// The resultant span in . /// The bit depth. - private void ScaleDownFrom8BitArray(ReadOnlySpan source, Span result, int bits) + /// The scaling factor. + private void ScaleDownFrom8BitArray(ReadOnlySpan source, Span result, int bits, float scale = 1) { ref byte sourceRef = ref MemoryMarshal.GetReference(source); ref byte resultRef = ref MemoryMarshal.GetReference(result); @@ -864,7 +876,7 @@ namespace SixLabors.ImageSharp.Formats.Png for (int i = 0; i < source.Length; i++) { - int value = Unsafe.Add(ref sourceRef, i) & mask; + int value = ((int)MathF.Round(Unsafe.Add(ref sourceRef, i) / scale)) & mask; v |= value << shift; if (shift == 0) diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/Alpha8.cs index 177ce81efd..91be2efdd2 100644 --- a/src/ImageSharp/PixelFormats/Alpha8.cs +++ b/src/ImageSharp/PixelFormats/Alpha8.cs @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator ==(Alpha8 left, Alpha8 right) => left.Equals(right); /// @@ -47,112 +47,60 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Alpha8 left, Alpha8 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(vector.W); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() => new Vector4(0, 0, 0, this.PackedValue / 255F); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) => this.PackedValue = source.A; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackedValue = source.A; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackedValue = source.A; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) => dest = default; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - dest.Rgb = default; - dest.A = this.PackedValue; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackedValue = byte.MaxValue; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - dest.R = 0; - dest.G = 0; - dest.B = 0; - dest.A = this.PackedValue; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackedValue = byte.MaxValue; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) => dest = default; + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackedValue = source.A; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - dest.R = 0; - dest.G = 0; - dest.B = 0; - dest.A = this.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(0, 0, 0, this.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackedValue = byte.MaxValue; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest = default; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromGray8(Gray8 source) => this.PackedValue = byte.MaxValue; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest = default; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromGray16(Gray16 source) => this.PackedValue = byte.MaxValue; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest = default; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) - { - dest.Rgb = default; - dest.A = ImageMaths.UpscaleFrom8BitTo16Bit(this.PackedValue); - } - /// /// Compares an object with the packed vector. /// @@ -165,17 +113,17 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The Alpha8 packed vector to compare. /// True if the packed vectors are equal. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(Alpha8 other) => this.PackedValue.Equals(other.PackedValue); /// /// Gets a string representation of the packed vector. /// /// A string representation of the packed vector. - public override string ToString() => (this.PackedValue / 255F).ToString(); + public override string ToString() => $"Alpha8({this.PackedValue})"; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); /// @@ -183,7 +131,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The float containing the value to pack. /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static byte Pack(float alpha) => (byte)Math.Round(alpha.Clamp(0, 1) * 255F); + [MethodImpl(InliningOptions.ShortMethod)] + private static byte Pack(float alpha) => (byte)Math.Round(alpha.Clamp(0, 1F) * 255F); } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Argb32.cs b/src/ImageSharp/PixelFormats/Argb32.cs index 0249bb6af9..0da8516a3e 100644 --- a/src/ImageSharp/PixelFormats/Argb32.cs +++ b/src/ImageSharp/PixelFormats/Argb32.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; using System.Runtime.InteropServices; @@ -58,7 +57,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The red component. /// The green component. /// The blue component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(byte r, byte g, byte b) { this.R = r; @@ -74,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(byte r, byte g, byte b, byte a) { this.R = r; @@ -90,12 +89,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(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. @@ -103,12 +99,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components for the packed vector. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(Vector3 vector) - : this() - { - this.Pack(ref vector); - } + : this() => this.Pack(ref vector); /// /// Initializes a new instance of the struct. @@ -116,12 +109,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components for the packed vector. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(Vector4 vector) - : this() - { - this.Pack(ref vector); - } + : this() => this.Pack(ref vector); /// /// Initializes a new instance of the struct. @@ -129,22 +119,19 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The packed value. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(uint packed) - : this() - { - this.Argb = packed; - } + : this() => this.Argb = packed; /// /// Gets or sets the packed representation of the Argb32 struct. /// public uint Argb { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => Unsafe.As(ref this); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; } @@ -158,20 +145,13 @@ 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. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Argb32 left, Argb32 right) - { - return left.Argb == right.Argb; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Argb32 left, Argb32 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -181,62 +161,34 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Argb32 left, Argb32 right) - { - return left.Argb != right.Argb; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.Pack(ref vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Argb32 left, Argb32 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackedValue = source.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackedValue = source.PackedValue; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) { this.R = source.R; @@ -245,164 +197,84 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = source.A; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - dest = this; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) { - this.A = 255; this.R = source.PackedValue; this.G = source.PackedValue; this.B = source.PackedValue; + this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) { - var val = (byte)(((source.PackedValue * 255) + 32895) >> 16); - this.R = val; - this.G = val; - this.B = val; - this.A = 255; + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; + this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = source.A; + } - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] + /// + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A); - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Bgra32 ToBgra32() => new Bgra32(this.R, this.G, this.B, this.A); - - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Argb32 ToArgb32() => this; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); - this.A = (byte)(((source.A * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); + this.A = ImageMaths.DownScaleFrom16BitTo8Bit(source.A); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + public override bool Equals(object obj) => obj is Argb32 argb32 && this.Equals(argb32); /// - public override bool Equals(object obj) - { - return obj is Argb32 argb32 && this.Equals(argb32); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Argb32 other) - { - return this.Argb == other.Argb; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Argb32 other) => this.Argb == other.Argb; /// /// Gets a string representation of the packed vector. /// /// A string representation of the packed vector. - public override string ToString() - { - return $"({this.R},{this.G},{this.B},{this.A})"; - } + public override string ToString() => $"Argb({this.A}, {this.R}, {this.G}, {this.B})"; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.Argb.GetHashCode(); /// /// Gets the representation without normalizing to [0, 1] /// /// A of values in [0, 255] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Vector4 ToByteScaledVector4() - { - return new Vector4(this.R, this.G, this.B, this.A); - } + [MethodImpl(InliningOptions.ShortMethod)] + internal Vector4 ToByteScaledVector4() => new Vector4(this.R, this.G, this.B, this.A); /// /// Packs the four floats into a color. @@ -411,7 +283,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The y-component /// The z-component /// The w-component - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(float x, float y, float z, float w) { var value = new Vector4(x, y, z, w); @@ -422,7 +294,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Packs a into a uint. /// /// The vector containing the values to pack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(ref Vector3 vector) { var value = new Vector4(vector, 1); @@ -433,7 +305,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Packs a into a color. /// /// The vector containing the values to pack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(ref Vector4 vector) { vector *= MaxBytes; diff --git a/src/ImageSharp/PixelFormats/Bgr24.cs b/src/ImageSharp/PixelFormats/Bgr24.cs index e1bb8a0ce1..063fed5221 100644 --- a/src/ImageSharp/PixelFormats/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/Bgr24.cs @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The red component. /// The green component. /// The blue component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Bgr24(byte r, byte g, byte b) { this.R = r; @@ -49,39 +49,54 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = b; } + /// + /// Compares two objects for equality. + /// + /// 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. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Bgr24 left, Bgr24 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Bgr24 left, Bgr24 right) => !left.Equals(right); + /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Bgr24 other) - { - return this.R == other.R && this.G == other.G && this.B == other.B; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - public override bool Equals(object obj) - { - return obj is Bgr24 other && this.Equals(other); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) { - int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); - return HashHelpers.Combine(hash, this.B.GetHashCode()); + Rgba32 rgba = default; + rgba.PackFromVector4(vector); + this.PackFromRgba32(rgba); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this = source.Bgr; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) { this.R = source.R; @@ -90,7 +105,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) { this.R = source.R; @@ -99,81 +114,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - Rgba32 rgba = default; - rgba.PackFromVector4(vector); - this.PackFromRgba32(rgba); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Rgba32(this.R, this.G, this.B, 255).ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; - } - - /// - public void ToBgr24(ref Bgr24 dest) - { - dest = this; - } - - /// - public void ToBgra32(ref Bgra32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) { this.R = source.PackedValue; @@ -182,53 +123,57 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) { - var val = (byte)(((source.PackedValue * 255) + 32895) >> 16); - this.R = val; - this.G = val; - this.B = val; + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this = source.Bgr; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, byte.MaxValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Bgr24 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); + + /// + public override bool Equals(object obj) => obj is Bgr24 other && this.Equals(other); /// - public override string ToString() + public override string ToString() => $"Bgra({this.B}, {this.G}, {this.R})"; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() { - return $"({this.B},{this.G},{this.R})"; + int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); + return HashHelpers.Combine(hash, this.B.GetHashCode()); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Bgr565.cs b/src/ImageSharp/PixelFormats/Bgr565.cs index 53f15ecb3b..5b19fb25c1 100644 --- a/src/ImageSharp/PixelFormats/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/Bgr565.cs @@ -8,7 +8,8 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.PixelFormats { /// - /// Packed pixel type containing unsigned normalized values ranging from 0 to 1. The x and z components use 5 bits, and the y component uses 6 bits. + /// Packed pixel type containing unsigned normalized values ranging from 0 to 1. + /// The x and z components use 5 bits, and the y component uses 6 bits. /// /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. /// @@ -22,8 +23,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// The y-component /// The z-component public Bgr565(float x, float y, float z) + : this(new Vector3(x, y, z)) { - this.PackedValue = Pack(x, y, z); } /// @@ -32,10 +33,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components for the packed value. /// - public Bgr565(Vector3 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z); - } + public Bgr565(Vector3 vector) => this.PackedValue = Pack(ref vector); /// public ushort PackedValue { get; set; } @@ -48,11 +46,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Bgr565 left, Bgr565 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Bgr565 left, Bgr565 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -62,199 +57,104 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Bgr565 left, Bgr565 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Bgr565 left, Bgr565 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); - /// - /// Expands the packed representation into a . - /// The vector components are typically expanded in least to greatest significance order. - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector3 ToVector3() - { - return new Vector3( - ((this.PackedValue >> 11) & 0x1F) * (1F / 31F), - ((this.PackedValue >> 5) & 0x3F) * (1F / 63F), - (this.PackedValue & 0x1F) * (1F / 31F)); - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z); + var vector3 = new Vector3(vector.X, vector.Y, vector.Z); + this.PackedValue = Pack(ref vector3); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.ToVector3(), 1F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.ToVector3(), 1F); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromVector4(source.ToVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromVector4(source.ToVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromVector4(source.ToVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override bool Equals(object obj) + /// + /// Expands the packed representation into a . + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public Vector3 ToVector3() { - return obj is Bgr565 other && this.Equals(other); + return new Vector3( + ((this.PackedValue >> 11) & 0x1F) * (1F / 31F), + ((this.PackedValue >> 5) & 0x3F) * (1F / 63F), + (this.PackedValue & 0x1F) * (1F / 31F)); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Bgr565 other) - { - return this.PackedValue == other.PackedValue; - } + public override bool Equals(object obj) => obj is Bgr565 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Bgr565 other) => this.PackedValue.Equals(other.PackedValue); /// public override string ToString() { - return this.ToVector3().ToString(); + var vector = this.ToVector3(); + return $"Bgr565({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##})"; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ushort Pack(float x, float y, float z) + [MethodImpl(InliningOptions.ShortMethod)] + private static ushort Pack(ref Vector3 vector) { - return (ushort)((((int)Math.Round(x.Clamp(0, 1) * 31F) & 0x1F) << 11) - | (((int)Math.Round(y.Clamp(0, 1) * 63F) & 0x3F) << 5) - | ((int)Math.Round(z.Clamp(0, 1) * 31F) & 0x1F)); + vector = Vector3.Clamp(vector, Vector3.Zero, Vector3.One); + + return (ushort)((((int)Math.Round(vector.X * 31F) & 0x1F) << 11) + | (((int)Math.Round(vector.Y * 63F) & 0x3F) << 5) + | ((int)Math.Round(vector.Z * 31F) & 0x1F)); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Bgra32.cs b/src/ImageSharp/PixelFormats/Bgra32.cs index c6fa4cf67e..6fd0867797 100644 --- a/src/ImageSharp/PixelFormats/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/Bgra32.cs @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The red component. /// The green component. /// The blue component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Bgra32(byte r, byte g, byte b) { this.R = r; @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Bgra32(byte r, byte g, byte b, byte a) { this.R = r; @@ -84,10 +84,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// public uint Bgra { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => Unsafe.As(ref this); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; } @@ -98,71 +98,49 @@ namespace SixLabors.ImageSharp.PixelFormats set => this.Bgra = value; } - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - public bool Equals(Bgra32 other) - { - return this.Bgra == other.Bgra; - } - - /// - public override bool Equals(object obj) => obj is Bgra32 other && this.Equals(other); - - /// - public override int GetHashCode() => this.Bgra.GetHashCode(); + /// + /// Compares two objects for equality. + /// + /// 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. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Bgra32 left, Bgra32 right) => left.Equals(right); /// - /// Gets the representation without normalizing to [0, 1] + /// Compares two objects for equality. /// - /// A of values in [0, 255] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Vector4 ToByteScaledVector4() - { - return new Vector4(this.R, this.G, this.B, this.A); - } + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Bgra32 left, Bgra32 right) => !left.Equals(right); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.Pack(ref vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) { this.R = source.R; @@ -172,132 +150,88 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackedValue = source.PackedValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackedValue = source.PackedValue; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) => dest = Unsafe.As(ref this); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) => dest = this; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) { this.R = source.PackedValue; - this.R = source.PackedValue; - this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) { - var val = (byte)(((source.PackedValue * 255) + 32895) >> 16); - this.R = val; - this.G = val; - this.B = val; + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = source.A; + } - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] + /// + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A); - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Argb32 ToArgb32() => new Argb32(this.R, this.G, this.B, this.A); - - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Bgra32 ToBgra32() => this; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); - this.A = (byte)(((source.A * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); + this.A = ImageMaths.DownScaleFrom16BitTo8Bit(source.A); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + public override bool Equals(object obj) => obj is Bgra32 other && this.Equals(other); + + /// + public bool Equals(Bgra32 other) => this.Bgra.Equals(other.Bgra); + + /// + public override int GetHashCode() => this.Bgra.GetHashCode(); + + /// + public override string ToString() => $"Bgra32({this.B}, {this.G}, {this.R}, {this.A})"; + + /// + /// Gets the representation without normalizing to [0, 1] + /// + /// A of values in [0, 255] + [MethodImpl(InliningOptions.ShortMethod)] + internal Vector4 ToByteScaledVector4() => new Vector4(this.R, this.G, this.B, this.A); /// /// Packs a into a color. /// /// The vector containing the values to pack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(ref Vector4 vector) { vector *= MaxBytes; @@ -309,11 +243,5 @@ 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 diff --git a/src/ImageSharp/PixelFormats/Bgra4444.cs b/src/ImageSharp/PixelFormats/Bgra4444.cs index f684bec339..8a5e3f76b3 100644 --- a/src/ImageSharp/PixelFormats/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/Bgra4444.cs @@ -23,18 +23,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// The z-component /// The w-component public Bgra4444(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - this.PackedValue = Pack(x, y, z, w); } /// /// Initializes a new instance of the struct. /// /// The vector containing the components for the packed vector. - public Bgra4444(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + public Bgra4444(Vector4 vector) => this.PackedValue = Pack(ref vector); /// public ushort PackedValue { get; set; } @@ -47,11 +44,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Bgra4444 left, Bgra4444 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Bgra4444 left, Bgra4444 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -61,193 +55,95 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Bgra4444 left, Bgra4444 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Bgra4444 left, Bgra4444 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { const float Max = 1 / 15F; return new Vector4( - ((this.PackedValue >> 8) & 0x0F) * Max, - ((this.PackedValue >> 4) & 0x0F) * Max, - (this.PackedValue & 0x0F) * Max, - ((this.PackedValue >> 12) & 0x0F) * Max); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; + (this.PackedValue >> 8) & 0x0F, + (this.PackedValue >> 4) & 0x0F, + this.PackedValue & 0x0F, + (this.PackedValue >> 12) & 0x0F) * Max; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override bool Equals(object obj) - { - return obj is Bgra4444 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Bgra4444 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Bgra4444 other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Bgra4444 other) => this.PackedValue.Equals(other.PackedValue); /// public override string ToString() { - return this.ToVector4().ToString(); + var vector = this.ToVector4(); + return $"Bgra4444({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})"; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ushort Pack(float x, float y, float z, float w) + [MethodImpl(InliningOptions.ShortMethod)] + private static ushort Pack(ref Vector4 vector) { - return (ushort)((((int)Math.Round(w.Clamp(0, 1) * 15F) & 0x0F) << 12) | - (((int)Math.Round(x.Clamp(0, 1) * 15F) & 0x0F) << 8) | - (((int)Math.Round(y.Clamp(0, 1) * 15F) & 0x0F) << 4) | - ((int)Math.Round(z.Clamp(0, 1) * 15F) & 0x0F)); + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); + return (ushort)((((int)Math.Round(vector.W * 15F) & 0x0F) << 12) + | (((int)Math.Round(vector.X * 15F) & 0x0F) << 8) + | (((int)Math.Round(vector.Y * 15F) & 0x0F) << 4) + | ((int)Math.Round(vector.Z * 15F) & 0x0F)); } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Bgra5551.cs b/src/ImageSharp/PixelFormats/Bgra5551.cs index 1044a0febf..25f289b846 100644 --- a/src/ImageSharp/PixelFormats/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/Bgra5551.cs @@ -8,7 +8,8 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.PixelFormats { /// - /// Packed pixel type containing unsigned normalized values ranging from 0 to 1. The x , y and z components use 5 bits, and the w component uses 1 bit. + /// Packed pixel type containing unsigned normalized values ranging from 0 to 1. + /// The x , y and z components use 5 bits, and the w component uses 1 bit. /// /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. /// @@ -23,8 +24,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// The z-component /// The w-component public Bgra5551(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - this.PackedValue = Pack(x, y, z, w); } /// @@ -33,10 +34,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components for the packed vector. /// - public Bgra5551(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + public Bgra5551(Vector4 vector) => this.PackedValue = Pack(ref vector); /// public ushort PackedValue { get; set; } @@ -49,11 +47,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Bgra5551 left, Bgra5551 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Bgra5551 left, Bgra5551 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -63,31 +58,26 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Bgra5551 left, Bgra5551 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Bgra5551 left, Bgra5551 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { return new Vector4( @@ -98,166 +88,67 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override bool Equals(object obj) - { - return obj is Bgra5551 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Bgra5551 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Bgra5551 other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Bgra5551 other) => this.PackedValue.Equals(other.PackedValue); - /// - /// Gets a string representation of the packed vector. - /// - /// A string representation of the packed vector. + /// public override string ToString() { - return this.ToVector4().ToString(); + var vector = this.ToVector4(); + return $"Bgra5551({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})"; } - /// - /// Gets a hash code of the packed vector. - /// - /// The hash code for the packed vector. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + /// + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ushort Pack(float x, float y, float z, float w) + [MethodImpl(InliningOptions.ShortMethod)] + private static ushort Pack(ref Vector4 vector) { + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); return (ushort)( - (((int)Math.Round(x.Clamp(0, 1) * 31F) & 0x1F) << 10) - | (((int)Math.Round(y.Clamp(0, 1) * 31F) & 0x1F) << 5) - | (((int)Math.Round(z.Clamp(0, 1) * 31F) & 0x1F) << 0) - | (((int)Math.Round(w.Clamp(0, 1)) & 0x1) << 15)); + (((int)Math.Round(vector.X * 31F) & 0x1F) << 10) + | (((int)Math.Round(vector.Y * 31F) & 0x1F) << 5) + | (((int)Math.Round(vector.Z * 31F) & 0x1F) << 0) + | (((int)Math.Round(vector.W) & 0x1) << 15)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() => this.ToVector4() * 255f; + [MethodImpl(InliningOptions.ShortMethod)] + private Vector4 ToByteScaledVector4() => this.ToVector4() * 255F; } -} +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Byte4.cs b/src/ImageSharp/PixelFormats/Byte4.cs index aea3aec655..fbdf4862db 100644 --- a/src/ImageSharp/PixelFormats/Byte4.cs +++ b/src/ImageSharp/PixelFormats/Byte4.cs @@ -21,10 +21,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// A vector containing the initial values for the components of the Byte4 structure. /// - public Byte4(Vector4 vector) - { - this.PackedValue = Pack(ref vector); - } + public Byte4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// /// Initializes a new instance of the struct. @@ -50,11 +47,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Byte4 left, Byte4 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Byte4 left, Byte4 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -64,38 +58,26 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Byte4 left, Byte4 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Byte4 left, Byte4 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector * 255F); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector * 255F); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4() / 255F; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4() / 255F; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(ref vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { return new Vector4( @@ -106,135 +88,53 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToByteScaledVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToByteScaledVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToByteScaledVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - var vector = this.ToVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - var vector = this.ToVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - var vector = this.ToVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromVector4(source.ToByteScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - var vector = this.ToVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - var vector = this.ToVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromVector4(source.ToByteScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override bool Equals(object obj) - { - return obj is Byte4 byte4 && this.Equals(byte4); - } + public override bool Equals(object obj) => obj is Byte4 byte4 && this.Equals(byte4); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Byte4 other) - { - return this == other; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Byte4 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - /// - /// Returns a string representation of the current instance. - /// - /// String that represents the object. + /// public override string ToString() { - return this.PackedValue.ToString("x8"); + var vector = this.ToVector4(); + return $"Bgra5551({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"; } /// @@ -242,18 +142,18 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the values to pack. /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static uint Pack(ref Vector4 vector) { const float Max = 255F; - const float Min = 0F; // Clamp the value between min and max values - // TODO: Use Vector4.Clamp() here! - uint byte4 = (uint)Math.Round(vector.X.Clamp(Min, Max)) & 0xFF; - uint byte3 = ((uint)Math.Round(vector.Y.Clamp(Min, Max)) & 0xFF) << 0x8; - uint byte2 = ((uint)Math.Round(vector.Z.Clamp(Min, Max)) & 0xFF) << 0x10; - uint byte1 = ((uint)Math.Round(vector.W.Clamp(Min, Max)) & 0xFF) << 0x18; + vector = Vector4.Clamp(vector, Vector4.Zero, new Vector4(Max)); + + uint byte4 = (uint)Math.Round(vector.X) & 0xFF; + uint byte3 = ((uint)Math.Round(vector.Y) & 0xFF) << 0x8; + uint byte2 = ((uint)Math.Round(vector.Z) & 0xFF) << 0x10; + uint byte1 = ((uint)Math.Round(vector.W) & 0xFF) << 0x18; return byte4 | byte3 | byte2 | byte1; } diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs index 50398eeb25..852ff73e0e 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs @@ -1,13 +1,4 @@ - - - - - - - - - -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. // @@ -55,10 +46,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromRgba64(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . /// /// The span of source pixels /// The destination span of data. @@ -74,7 +63,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToRgba64(ref dp); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } @@ -127,10 +116,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromRgb48(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . /// /// The span of source pixels /// The destination span of data. @@ -146,7 +133,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToRgb48(ref dp); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } @@ -199,10 +186,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromRgba32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . /// /// The span of source pixels /// The destination span of data. @@ -218,7 +203,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToRgba32(ref dp); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } @@ -271,10 +256,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromBgra32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . /// /// The span of source pixels /// The destination span of data. @@ -290,7 +273,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToBgra32(ref dp); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } @@ -343,10 +326,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromRgb24(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . /// /// The span of source pixels /// The destination span of data. @@ -362,7 +343,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToRgb24(ref dp); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } @@ -415,10 +396,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromBgr24(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . /// /// The span of source pixels /// The destination span of data. @@ -434,7 +413,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToBgr24(ref dp); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } @@ -487,10 +466,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromArgb32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . /// /// The span of source pixels /// The destination span of data. @@ -506,7 +483,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Argb32 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToArgb32(ref dp); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } @@ -559,10 +536,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromGray8(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . /// /// The span of source pixels /// The destination span of data. @@ -578,7 +553,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Gray8 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToGray8(ref dp); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } @@ -594,5 +569,75 @@ namespace SixLabors.ImageSharp.PixelFormats { this.ToGray8(sourceColors, MemoryMarshal.Cast(destBytes), count); } + + /// + /// 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 PackFromGray16(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + ref Gray16 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++) + { + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + temp = Unsafe.Add(ref sourceRef, i); + dp.PackFromGray16(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 PackFromGray16Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + { + this.PackFromGray16(MemoryMarshal.Cast(sourceBytes), destPixels, count); + } + /// + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// + /// The span of source pixels + /// The destination span of data. + /// The number of pixels to convert. + internal virtual void ToGray16(ReadOnlySpan sourcePixels, Span dest, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + + ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destBaseRef = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destBaseRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); + } + } + + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// The to the source colors. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToGray16Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + { + this.ToGray16(sourceColors, MemoryMarshal.Cast(destBytes), count); + } } } \ 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 b4b577e3ab..9fbe57ed9b 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt @@ -14,6 +14,7 @@ void GeneratePackFromMethods(string pixelType, string tempPixelType, string assignToTempCode) { #> + /// /// Converts 'count' elements in 'source` span of data to a span of -s. /// @@ -58,7 +59,6 @@ #> /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . /// /// The span of source pixels /// The destination span of data. @@ -74,7 +74,7 @@ { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destBaseRef, i); - sp.To<#=pixelType#>(ref dp); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } @@ -130,5 +130,9 @@ namespace SixLabors.ImageSharp.PixelFormats GeneratePackFromMethods("Gray8", "Gray8", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Gray8"); + + GeneratePackFromMethods("Gray16", "Gray16", "temp = Unsafe.Add(ref sourceRef, i);"); + GenerateToDestFormatMethods("Gray16"); + #> } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs index e68efba252..9621505952 100644 --- a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - Unsafe.As(ref dp) = sp; dp.A = 255; + Unsafe.As(ref dp) = sp; dp.A = byte.MaxValue; } } @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.Bgr = sp; dp.A = 255; + dp.Bgr = sp; dp.A = byte.MaxValue; } } @@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToRgba32(); + dp.R = sp.R; dp.G = sp.G; dp.B = sp.B; dp.A = sp.A; } } @@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToBgra32(); + dp.PackFromRgba32(sp); } } @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToRgba32(); + dp.R = sp.R; dp.G = sp.G; dp.B = sp.B; dp.A = sp.A; } } @@ -140,7 +140,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToArgb32(); + dp.PackFromRgba32(sp); } } diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt index a734333390..9d9145f0b9 100644 --- a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt @@ -71,17 +71,17 @@ namespace SixLabors.ImageSharp.PixelFormats internal partial class PixelOperations { <# - GeneratePackFromMethod("Rgb24", "Unsafe.As(ref dp) = sp; dp.A = 255;"); + GeneratePackFromMethod("Rgb24", "Unsafe.As(ref dp) = sp; dp.A = byte.MaxValue;"); GenerateConvertToMethod("Rgb24", "dp = Unsafe.As(ref sp);"); - GeneratePackFromMethod("Bgr24", "dp.Bgr = sp; dp.A = 255;"); + GeneratePackFromMethod("Bgr24", "dp.Bgr = sp; dp.A = byte.MaxValue;"); GenerateConvertToMethod("Bgr24", "dp = sp.Bgr;"); - GeneratePackFromMethod("Bgra32", "dp = sp.ToRgba32();"); - GenerateConvertToMethod("Bgra32", "dp = sp.ToBgra32();"); + GeneratePackFromMethod("Bgra32", "dp.R = sp.R; dp.G = sp.G; dp.B = sp.B; dp.A = sp.A;"); + GenerateConvertToMethod("Bgra32", "dp.PackFromRgba32(sp);"); - GeneratePackFromMethod("Argb32", "dp = sp.ToRgba32();"); - GenerateConvertToMethod("Argb32", "dp = sp.ToArgb32();"); + GeneratePackFromMethod("Argb32", "dp.R = sp.R; dp.G = sp.G; dp.B = sp.B; dp.A = sp.A;"); + GenerateConvertToMethod("Argb32", "dp.PackFromRgba32(sp);"); #> } diff --git a/src/ImageSharp/PixelFormats/Gray16.cs b/src/ImageSharp/PixelFormats/Gray16.cs index 06da2867a9..f9aada9374 100644 --- a/src/ImageSharp/PixelFormats/Gray16.cs +++ b/src/ImageSharp/PixelFormats/Gray16.cs @@ -15,29 +15,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct Gray16 : IPixel, IPackedVector { - /// - /// RX as in ITU-R recommendation 709 to match libpng - /// - private const float Rx = .2126F; - - /// - /// GX as in ITU-R recommendation 709 to match libpng - /// - private const float Gx = .7152F; - - /// - /// BX as in ITU-R recommendation 709 to match libpng - /// - private const float Bx = .0722F; + private const float Max = ushort.MaxValue; /// /// Initializes a new instance of the struct. /// - /// The gray component - public Gray16(ushort gray) - { - this.PackedValue = gray; - } + /// The luminance component + public Gray16(ushort luminance) => this.PackedValue = luminance; /// public ushort PackedValue { get; set; } @@ -45,20 +29,13 @@ 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. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Gray16 left, Gray16 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Gray16 left, Gray16 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -68,230 +45,105 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Gray16 left, Gray16 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Gray16 left, Gray16 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - var scaledGray = this.PackedValue / 65535f; // ushort.Max as float - return new Vector4(scaledGray, scaledGray, scaledGray, 1.0f); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z); + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + (ushort)MathF.Round(vector.X), + (ushort)MathF.Round(vector.Y), + (ushort)MathF.Round(vector.Z)); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { - return new Vector4(this.PackedValue, this.PackedValue, this.PackedValue, 1.0f); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackedValue = Pack(source.R, source.G, source.B); + float scaled = this.PackedValue / Max; + return new Vector4(scaled, scaled, scaled, 1F); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) { - this.PackedValue = Pack(source.R, source.G, source.B); + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) { - this.PackedValue = Pack(source.R, source.G, source.B); + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - var scaledValue = this.PackedAsByte(); - - dest.R = scaledValue; - dest.G = scaledValue; - dest.B = scaledValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackedValue = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - var scaledValue = this.PackedAsByte(); - - dest.R = scaledValue; - dest.G = scaledValue; - dest.B = scaledValue; - dest.A = 255; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackedValue = source.PackedValue; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) { - var scaledValue = this.PackedAsByte(); - - dest.R = scaledValue; - dest.G = scaledValue; - dest.B = scaledValue; - dest.A = 255; + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() { - var scaledValue = this.PackedAsByte(); - - dest.R = scaledValue; - dest.G = scaledValue; - dest.B = scaledValue; + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(this.PackedValue); + return new Rgba32(rgb, rgb, rgb, byte.MaxValue); } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - var scaledValue = this.PackedAsByte(); - - dest.R = scaledValue; - dest.G = scaledValue; - dest.B = scaledValue; - dest.A = 255; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackedValue = ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromGray8(Gray8 source) - { - this.PackedValue = (ushort)(source.PackedValue * 255); - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba64(Rgba64 source) => ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) - { - dest.PackedValue = (byte)(((this.PackedValue * 255) + 32895) >> 16); - } + public override bool Equals(object obj) => obj is Gray16 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromGray16(Gray16 source) - { - this.PackedValue = source.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Gray16 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) - { - dest.PackedValue = this.PackedValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => - this.PackedValue = Pack(source.R, source.G, source.B); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) - { - dest.R = this.PackedValue; - dest.G = this.PackedValue; - dest.B = this.PackedValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => - this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - /// Compares an object with the packed vector. - /// - /// The object to compare. - /// True if the object is equal to the packed vector. - public override bool Equals(object obj) - { - return obj is Gray16 other && this.Equals(other); - } - - /// - /// Compares another packed vector with the packed vector. - /// - /// The Gray8 packed vector to compare. - /// True if the packed vectors are equal. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Gray16 other) - { - return this.PackedValue == other.PackedValue; - } - - /// - /// Gets a string representation of the packed vector. - /// - /// A string representation of the packed vector. - public override string ToString() - { - return (this.PackedValue / 65535f).ToString(); - } + public override string ToString() => $"Gray16({this.PackedValue})"; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - - /// - /// Packs a into a byte. - /// - /// Red value of the color to pack. - /// Green value of the color to pack. - /// Blue value of the color to pack. - /// The containing the packed value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ushort Pack(float r, float g, float b) - { - float val = (r * Rx) + (g * Gx) + (b * Bx); - return (ushort)Math.Round(val * 65535f); - } - - /// - /// Packs the into a byte. - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private byte PackedAsByte() - { - return (byte)(this.PackedValue >> 8); - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Gray8.cs b/src/ImageSharp/PixelFormats/Gray8.cs index 0a41a6ecc6..b1fa2b1e14 100644 --- a/src/ImageSharp/PixelFormats/Gray8.cs +++ b/src/ImageSharp/PixelFormats/Gray8.cs @@ -14,21 +14,6 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct Gray8 : IPixel, IPackedVector { - /// - /// RX as in ITU-R recommendation 709 to match libpng - /// - private const float Rx = .2126F; - - /// - /// GX as in ITU-R recommendation 709 to match libpng - /// - private const float Gx = .7152F; - - /// - /// BX as in ITU-R recommendation 709 to match libpng - /// - private const float Bx = .0722F; - /// /// The maximum byte value. /// @@ -42,8 +27,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Initializes a new instance of the struct. /// - /// The gray component - public Gray8(byte gray) => this.PackedValue = gray; + /// The luminance component. + public Gray8(byte luminance) => this.PackedValue = luminance; /// public byte PackedValue { get; set; } @@ -57,7 +42,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// True if the parameter is equal to the parameter; otherwise, false. /// [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator ==(Gray8 left, Gray8 right) => left.PackedValue.Equals(right.PackedValue); + public static bool operator ==(Gray8 left, Gray8 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -68,7 +53,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// True if the parameter is not equal to the parameter; otherwise, false. /// [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator !=(Gray8 left, Gray8 right) => !left.PackedValue.Equals(right.PackedValue); + public static bool operator !=(Gray8 left, Gray8 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); @@ -88,9 +73,8 @@ namespace SixLabors.ImageSharp.PixelFormats vector *= MaxBytes; vector += Half; vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - float luminance = (vector.X * Rx) + (vector.Y * Gx) + (vector.Z * Bx); - this.PackedValue = (byte)luminance; + this.PackedValue = ImageMaths.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z); } /// @@ -101,138 +85,54 @@ namespace SixLabors.ImageSharp.PixelFormats return new Vector4(rgb, rgb, rgb, 1F); } - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackedValue = ImageMaths.GetBT709LuminanceBytes(source.R, source.G, source.B); - /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackedValue = ImageMaths.GetBT709LuminanceBytes(source.R, source.G, source.B); + public void PackFromArgb32(Argb32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackedValue = ImageMaths.GetBT709LuminanceBytes(source.R, source.G, source.B); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgb24(ref Rgb24 dest) - { - dest.R = this.PackedValue; - dest.G = this.PackedValue; - dest.B = this.PackedValue; - } + public void PackFromBgra32(Bgra32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); - /// + /// [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.PackedValue; - dest.G = this.PackedValue; - dest.B = this.PackedValue; - dest.A = byte.MaxValue; - } + public void PackFromGray8(Gray8 source) => this.PackedValue = source.PackedValue; - /// + /// [MethodImpl(InliningOptions.ShortMethod)] - public void ToArgb32(ref Argb32 dest) - { - dest.R = this.PackedValue; - dest.G = this.PackedValue; - dest.B = this.PackedValue; - dest.A = byte.MaxValue; - } + public void PackFromGray16(Gray16 source) => this.PackedValue = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); /// [MethodImpl(InliningOptions.ShortMethod)] - public void ToBgr24(ref Bgr24 dest) - { - dest.R = this.PackedValue; - dest.G = this.PackedValue; - dest.B = this.PackedValue; - } + public void PackFromRgba32(Rgba32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); /// [MethodImpl(InliningOptions.ShortMethod)] - public void ToBgra32(ref Bgra32 dest) - { - dest.R = this.PackedValue; - dest.G = this.PackedValue; - dest.B = this.PackedValue; - dest.A = byte.MaxValue; - } + public Rgba32 ToRgba32() => new Rgba32(this.PackedValue, this.PackedValue, this.PackedValue, byte.MaxValue); /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) - => this.PackedValue = ImageMaths.GetBT709LuminanceBytes( + => this.PackedValue = ImageMaths.Get8BitBT709Luminance( ImageMaths.DownScaleFrom16BitTo8Bit(source.R), ImageMaths.DownScaleFrom16BitTo8Bit(source.G), ImageMaths.DownScaleFrom16BitTo8Bit(source.B)); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgb48(ref Rgb48 dest) - { - ushort luminance = ImageMaths.UpscaleFrom8BitTo16Bit(this.PackedValue); - dest.R = luminance; - dest.G = luminance; - dest.B = luminance; - } - /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) - => this.PackedValue = ImageMaths.GetBT709LuminanceBytes( + => this.PackedValue = ImageMaths.Get8BitBT709Luminance( ImageMaths.DownScaleFrom16BitTo8Bit(source.R), ImageMaths.DownScaleFrom16BitTo8Bit(source.G), ImageMaths.DownScaleFrom16BitTo8Bit(source.B)); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackedValue = source.PackedValue; - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackedValue = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba64(ref Rgba64 dest) - { - ushort luminance = ImageMaths.UpscaleFrom8BitTo16Bit(this.PackedValue); - dest.R = luminance; - dest.G = luminance; - dest.B = luminance; - dest.A = ushort.MaxValue; - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToGray8(ref Gray8 dest) => dest.PackedValue = this.PackedValue; - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToGray16(ref Gray16 dest) => dest.PackedValue = ImageMaths.UpscaleFrom8BitTo16Bit(this.PackedValue); - - /// - /// Compares an object with the packed vector. - /// - /// The object to compare. - /// True if the object is equal to the packed vector. + /// public override bool Equals(object obj) => obj is Gray8 other && this.Equals(other); - /// - /// Compares another packed vector with the packed vector. - /// - /// The Gray8 packed vector to compare. - /// True if the packed vectors are equal. + /// [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(Gray8 other) => this.PackedValue.Equals(other.PackedValue); - /// - /// Gets a string representation of the packed vector. - /// - /// A string representation of the packed vector. + /// public override string ToString() => $"Gray8({this.PackedValue}"; /// diff --git a/src/ImageSharp/PixelFormats/HalfSingle.cs b/src/ImageSharp/PixelFormats/HalfSingle.cs index b392910a67..8048a3825d 100644 --- a/src/ImageSharp/PixelFormats/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/HalfSingle.cs @@ -28,10 +28,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Initializes a new instance of the struct. /// /// The single component. - public HalfSingle(float single) - { - this.PackedValue = HalfTypeHelper.Pack(single); - } + public HalfSingle(float single) => this.PackedValue = HalfTypeHelper.Pack(single); /// public ushort PackedValue { get; set; } @@ -39,222 +36,115 @@ 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. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(HalfSingle left, HalfSingle right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(HalfSingle left, HalfSingle right) => left.Equals(right); /// /// 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 not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(HalfSingle left, HalfSingle right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(HalfSingle left, HalfSingle right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); - /// - /// Expands the packed representation into a . - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public float ToSingle() - { - return HalfTypeHelper.Unpack(this.PackedValue); - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { float scaled = vector.X; scaled *= 2F; - scaled -= 1F; + scaled--; this.PackedValue = HalfTypeHelper.Pack(scaled); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { float single = this.ToSingle() + 1F; single /= 2F; - return new Vector4(single, 0, 0, 1); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = HalfTypeHelper.Pack(vector.X); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.ToSingle(), 0, 0, 1); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; + return new Vector4(single, 0, 0, 1F); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = HalfTypeHelper.Pack(vector.X); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.ToSingle(), 0, 0, 1F); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + /// Expands the packed representation into a . + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public float ToSingle() => HalfTypeHelper.Unpack(this.PackedValue); /// - public override bool Equals(object obj) - { - return obj is HalfSingle other && this.Equals(other); - } + public override bool Equals(object obj) => obj is HalfSingle other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(HalfSingle other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(HalfSingle other) => this.PackedValue.Equals(other.PackedValue); /// - public override string ToString() - { - return this.ToSingle().ToString(); - } + public override string ToString() => $"HalfSingle({this.ToSingle():#0.##})"; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private Vector4 ToByteScaledVector4() { var vector = this.ToVector4(); vector *= MaxBytes; vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; + return Vector4.Clamp(vector, Vector4.Zero, MaxBytes); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/HalfTypeHelper.cs b/src/ImageSharp/PixelFormats/HalfTypeHelper.cs index cf8b9f4a23..e8cfaa462e 100644 --- a/src/ImageSharp/PixelFormats/HalfTypeHelper.cs +++ b/src/ImageSharp/PixelFormats/HalfTypeHelper.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Helper methods for packing and unpacking floating point values /// - internal class HalfTypeHelper + internal static class HalfTypeHelper { /// /// Packs a into an @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.PixelFormats return (ushort)s; } - m = m | 0x00800000; + m |= 0x00800000; int t = 14 - e; int a = (1 << (t - 1)) - 1; @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.PixelFormats if ((m & 0x00800000) != 0) { m = 0; - e += 1; + e++; } if (e > 30) @@ -97,11 +97,11 @@ namespace SixLabors.ImageSharp.PixelFormats while ((mantissa & 1024) == 0) { exponent--; - mantissa = mantissa << 1; + mantissa <<= 1; } mantissa &= 0xfffffbff; - result = ((uint)((((uint)value & 0x8000) << 16) | ((exponent + 127) << 23))) | (mantissa << 13); + result = (((uint)value & 0x8000) << 16) | ((exponent + 127) << 23) | (mantissa << 13); } else { @@ -110,7 +110,7 @@ namespace SixLabors.ImageSharp.PixelFormats } else { - result = ((((uint)value & 0x8000) << 16) | ((((((uint)value >> 10) & 0x1f) - 15) + 127) << 23)) | (mantissa << 13); + result = (((uint)value & 0x8000) << 16) | ((((((uint)value >> 10) & 0x1f) - 15) + 127) << 23) | (mantissa << 13); } var uif = new Uif { U = result }; diff --git a/src/ImageSharp/PixelFormats/HalfVector2.cs b/src/ImageSharp/PixelFormats/HalfVector2.cs index ac70f4fbcc..f398f508ba 100644 --- a/src/ImageSharp/PixelFormats/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/HalfVector2.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; @@ -15,34 +14,18 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct HalfVector2 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half vector value. - /// - private static readonly Vector4 Half = new Vector4(0.5F); - /// /// Initializes a new instance of the struct. /// /// The x-component. /// The y-component. - public HalfVector2(float x, float y) - { - this.PackedValue = Pack(x, y); - } + public HalfVector2(float x, float y) => this.PackedValue = Pack(x, y); /// /// Initializes a new instance of the struct. /// /// A vector containing the initial values for the components. - public HalfVector2(Vector2 vector) - { - this.PackedValue = Pack(vector.X, vector.Y); - } + public HalfVector2(Vector2 vector) => this.PackedValue = Pack(vector.X, vector.Y); /// public uint PackedValue { get; set; } @@ -50,57 +33,30 @@ 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. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(HalfVector2 left, HalfVector2 right) - { - return left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(HalfVector2 left, HalfVector2 right) => left.Equals(right); /// /// 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 not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(HalfVector2 left, HalfVector2 right) - { - return !left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(HalfVector2 left, HalfVector2 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); - /// - /// Expands the packed representation into a . - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector2 ToVector2() - { - Vector2 vector; - vector.X = HalfTypeHelper.Unpack((ushort)this.PackedValue); - vector.Y = HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x10)); - return vector; - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; @@ -109,7 +65,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector2(); @@ -119,14 +75,11 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(vector.X, vector.Y); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { var vector = this.ToVector2(); @@ -134,156 +87,74 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override string ToString() + /// + /// Expands the packed representation into a . + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public Vector2 ToVector2() { - return this.ToVector2().ToString(); + Vector2 vector; + vector.X = HalfTypeHelper.Unpack((ushort)this.PackedValue); + vector.Y = HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x10)); + return vector; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() => this.PackedValue.GetHashCode(); + public override bool Equals(object obj) => obj is HalfVector2 other && this.Equals(other); /// - public override bool Equals(object obj) - { - return obj is HalfVector2 other && this.Equals(other); - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(HalfVector2 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(HalfVector2 other) + public override string ToString() { - return this.PackedValue.Equals(other.PackedValue); + var vector = this.ToVector2(); + return $"HalfVector2({vector.X:#0.##}, {vector.Y:#0.##})"; } - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + [MethodImpl(InliningOptions.ShortMethod)] private static uint Pack(float x, float y) { uint num2 = HalfTypeHelper.Pack(x); uint num = (uint)(HalfTypeHelper.Pack(y) << 0x10); return num2 | num; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/HalfVector4.cs b/src/ImageSharp/PixelFormats/HalfVector4.cs index 9bdae99abe..45d93efc09 100644 --- a/src/ImageSharp/PixelFormats/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/HalfVector4.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; @@ -15,16 +14,6 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct HalfVector4 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half vector value. - /// - private static readonly Vector4 Half = new Vector4(0.5F); - /// /// Initializes a new instance of the struct. /// @@ -33,64 +22,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// The z-component. /// The w-component. public HalfVector4(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - var vector = new Vector4(x, y, z, w); - this.PackedValue = Pack(ref vector); } /// /// Initializes a new instance of the struct. /// /// A vector containing the initial values for the components - public HalfVector4(Vector4 vector) - { - this.PackedValue = Pack(ref vector); - } + public HalfVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// public ulong PackedValue { get; set; } /// - /// Compares two objects for equality. + /// 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. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(HalfVector4 left, HalfVector4 right) - { - return left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(HalfVector4 left, HalfVector4 right) => left.Equals(right); /// - /// Compares two objects for equality. + /// 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 not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(HalfVector4 left, HalfVector4 right) - { - return !left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(HalfVector4 left, HalfVector4 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { vector *= 2F; @@ -99,7 +70,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector4(); @@ -109,14 +80,11 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(ref vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { return new Vector4( @@ -127,140 +95,61 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override string ToString() - { - return this.ToVector4().ToString(); - } + public override bool Equals(object obj) => obj is HalfVector4 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() => this.PackedValue.GetHashCode(); + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(HalfVector4 other) => this.PackedValue.Equals(other.PackedValue); /// - public override bool Equals(object obj) + public override string ToString() { - return obj is HalfVector4 other && this.Equals(other); + var vector = this.ToVector4(); + return $"HalfVector4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(HalfVector4 other) - { - return this.PackedValue.Equals(other.PackedValue); - } + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); /// /// Packs a into a . /// /// The vector containing the values to pack. /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static ulong Pack(ref Vector4 vector) { ulong num4 = HalfTypeHelper.Pack(vector.X); @@ -269,15 +158,5 @@ namespace SixLabors.ImageSharp.PixelFormats ulong num1 = (ulong)HalfTypeHelper.Pack(vector.W) << 0x30; return num4 | num3 | num2 | num1; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index 382c8541d6..a3017501ce 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -28,12 +28,6 @@ namespace SixLabors.ImageSharp.PixelFormats /// public interface IPixel { - /// - /// Sets the packed representation from a . - /// - /// The vector to create the packed representation from. - void PackFromVector4(Vector4 vector); - /// /// Sets the packed representation from a scaled . /// @@ -48,6 +42,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// The . Vector4 ToScaledVector4(); + /// + /// Sets the packed representation from a . + /// + /// The vector to create the packed representation from. + void PackFromVector4(Vector4 vector); + /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. @@ -55,24 +55,6 @@ namespace SixLabors.ImageSharp.PixelFormats /// The . Vector4 ToVector4(); - /// - /// Packs the pixel from an value. - /// - /// The value. - void PackFromRgba32(Rgba32 source); - - /// - /// Packs the pixel from an value. - /// - /// The value. - void PackFromRgb48(Rgb48 source); - - /// - /// Packs the pixel from an value. - /// - /// The value. - void PackFromRgba64(Rgba64 source); - /// /// Packs the pixel from an value. /// @@ -86,69 +68,39 @@ namespace SixLabors.ImageSharp.PixelFormats void PackFromBgra32(Bgra32 source); /// - /// Converts the pixel to format. - /// - /// The destination pixel to write to - void ToRgb24(ref Rgb24 dest); - - /// - /// Converts the pixel to format. - /// - /// The destination pixel to write to - void ToRgba32(ref Rgba32 dest); - - /// - /// Converts the pixel to format. - /// - /// The destination pixel to write to - void ToRgb48(ref Rgb48 dest); - - /// - /// Converts the pixel to format. - /// - /// The destination pixel to write to - void ToRgba64(ref Rgba64 dest); - - /// - /// Converts the pixel to format. - /// - /// The destination pixel to write to - void ToArgb32(ref Argb32 dest); - - /// - /// Converts the pixel to format. + /// Packs the Pixel from an value. /// - /// The destination pixel to write to - void ToBgr24(ref Bgr24 dest); + /// The value. + void PackFromGray8(Gray8 source); /// - /// Converts the pixel to format. + /// Packs the Pixel from an value. /// - /// The destination pixel to write to - void ToBgra32(ref Bgra32 dest); + /// The value. + void PackFromGray16(Gray16 source); /// - /// Packs the Pixel from an value. + /// Packs the pixel from an value. /// - /// The value. - void PackFromGray8(Gray8 source); + /// The value. + void PackFromRgba32(Rgba32 source); /// - /// Converts the pixel to format. + /// Expands the packed representation into an . /// - /// The destination pixel to write to. - void ToGray8(ref Gray8 dest); + /// The . + Rgba32 ToRgba32(); /// - /// Packs the Pixel from an value. + /// Packs the pixel from an value. /// - /// The value. - void PackFromGray16(Gray16 source); + /// The value. + void PackFromRgb48(Rgb48 source); /// - /// Converts the pixel tgo value. + /// Packs the pixel from an value. /// - /// The destination pixel to write to. - void ToGray16(ref Gray16 dest); + /// The value. + void PackFromRgba64(Rgba64 source); } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/NormalizedByte2.cs index cd9fa65fbe..86b5280902 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte2.cs @@ -15,39 +15,24 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct NormalizedByte2 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half the maximum byte value. - /// - private static readonly Vector4 Half = new Vector4(127); - - /// - /// The vector value used for rounding. - /// - private static readonly Vector4 Round = new Vector4(.5F); + private static readonly Vector2 Half = new Vector2(127); + private static readonly Vector2 MinusOne = new Vector2(-1F); /// /// Initializes a new instance of the struct. /// - /// The vector containing the component values. - public NormalizedByte2(Vector2 vector) + /// The x-component. + /// The y-component. + public NormalizedByte2(float x, float y) + : this(new Vector2(x, y)) { - this.PackedValue = Pack(vector.X, vector.Y); } /// /// Initializes a new instance of the struct. /// - /// The x-component. - /// The y-component. - public NormalizedByte2(float x, float y) - { - this.PackedValue = Pack(x, y); - } + /// The vector containing the component values. + public NormalizedByte2(Vector2 vector) => this.PackedValue = Pack(vector); /// public ushort PackedValue { get; set; } @@ -55,66 +40,39 @@ 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. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(NormalizedByte2 left, NormalizedByte2 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(NormalizedByte2 left, NormalizedByte2 right) => left.Equals(right); /// /// 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 not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(NormalizedByte2 left, NormalizedByte2 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(NormalizedByte2 left, NormalizedByte2 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); - /// - /// Expands the packed representation into a . - /// The vector components are typically expanded in least to greatest significance order. - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector2 ToVector2() - { - return new Vector2( - (sbyte)((this.PackedValue >> 0) & 0xFF) / 127F, - (sbyte)((this.PackedValue >> 8) & 0xFF) / 127F); - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; scaled -= Vector2.One; - this.PackedValue = Pack(scaled.X, scaled.Y); + this.PackedValue = Pack(scaled); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector2(); @@ -124,188 +82,89 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { - this.PackedValue = Pack(vector.X, vector.Y); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.ToVector2(), 0F, 1F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); + var vector2 = new Vector2(vector.X, vector.Y); + this.PackedValue = Pack(vector2); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.ToVector2(), 0F, 1F); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override bool Equals(object obj) + /// + /// Expands the packed representation into a . + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public Vector2 ToVector2() { - return obj is NormalizedByte2 other && this.Equals(other); + return new Vector2( + (sbyte)((this.PackedValue >> 0) & 0xFF) / 127F, + (sbyte)((this.PackedValue >> 8) & 0xFF) / 127F); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(NormalizedByte2 other) - { - return this.PackedValue == other.PackedValue; - } + public override bool Equals(object obj) => obj is NormalizedByte2 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(NormalizedByte2 other) => this.PackedValue.Equals(other.PackedValue); + + /// + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); /// public override string ToString() { - return this.PackedValue.ToString("X"); + var vector = this.ToVector2(); + return $"NormalizedByte2({vector.X:#0.##}, {vector.Y:#0.##})"; } - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ushort Pack(float x, float y) + [MethodImpl(InliningOptions.ShortMethod)] + private static ushort Pack(Vector2 vector) { - int byte2 = ((ushort)Math.Round(x.Clamp(-1F, 1F) * 127F) & 0xFF) << 0; - int byte1 = ((ushort)Math.Round(y.Clamp(-1F, 1F) * 127F) & 0xFF) << 8; + vector = Vector2.Clamp(vector, MinusOne, Vector2.One) * Half; - return (ushort)(byte2 | byte1); - } + int byte2 = ((ushort)Math.Round(vector.X) & 0xFF) << 0; + int byte1 = ((ushort)Math.Round(vector.Y) & 0xFF) << 8; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; + return (ushort)(byte2 | byte1); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/NormalizedByte4.cs index 9b53adeccf..b538e4a449 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte4.cs @@ -15,29 +15,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct NormalizedByte4 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half the maximum byte value. - /// private static readonly Vector4 Half = new Vector4(127); - - /// - /// The vector value used for rounding. - /// - private static readonly Vector4 Round = new Vector4(.5F); - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the component values. - public NormalizedByte4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + private static readonly Vector4 MinusOne = new Vector4(-1F); /// /// Initializes a new instance of the struct. @@ -47,54 +26,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// The z-component. /// The w-component. public NormalizedByte4(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - this.PackedValue = Pack(x, y, z, w); } + /// + /// Initializes a new instance of the struct. + /// + /// The vector containing the component values. + public NormalizedByte4(Vector4 vector) => this.PackedValue = Pack(ref vector); + /// public uint PackedValue { get; set; } /// /// 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. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(NormalizedByte4 left, NormalizedByte4 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(NormalizedByte4 left, NormalizedByte4 right) => left.Equals(right); /// /// 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 not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(NormalizedByte4 left, NormalizedByte4 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(NormalizedByte4 left, NormalizedByte4 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { vector *= 2F; @@ -103,7 +74,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector4(); @@ -113,14 +84,11 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { return new Vector4( @@ -131,178 +99,66 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override bool Equals(object obj) - { - return obj is NormalizedByte4 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is NormalizedByte4 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(NormalizedByte4 other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(NormalizedByte4 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); /// public override string ToString() { - return this.PackedValue.ToString("X"); + var vector = this.ToVector4(); + return $"NormalizedByte4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"; } - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Pack(float x, float y, float z, float w) + [MethodImpl(InliningOptions.ShortMethod)] + private static uint Pack(ref Vector4 vector) { - uint byte4 = ((uint)Math.Round(x.Clamp(-1F, 1F) * 127F) & 0xFF) << 0; - uint byte3 = ((uint)Math.Round(y.Clamp(-1F, 1F) * 127F) & 0xFF) << 8; - uint byte2 = ((uint)Math.Round(z.Clamp(-1F, 1F) * 127F) & 0xFF) << 16; - uint byte1 = ((uint)Math.Round(w.Clamp(-1F, 1F) * 127F) & 0xFF) << 24; + vector = Vector4.Clamp(vector, MinusOne, Vector4.One) * Half; - return byte4 | byte3 | byte2 | byte1; - } + uint byte4 = ((uint)Math.Round(vector.X) & 0xFF) << 0; + uint byte3 = ((uint)Math.Round(vector.Y) & 0xFF) << 8; + uint byte2 = ((uint)Math.Round(vector.Z) & 0xFF) << 16; + uint byte1 = ((uint)Math.Round(vector.W) & 0xFF) << 24; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; + return byte4 | byte3 | byte2 | byte1; } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/NormalizedShort2.cs index 3319a10927..6135826f48 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort2.cs @@ -15,39 +15,24 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct NormalizedShort2 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half the maximum byte value. - /// - private static readonly Vector4 Half = new Vector4(127); - - /// - /// The vector value used for rounding. - /// - private static readonly Vector4 Round = new Vector4(.5F); + private static readonly Vector2 Max = new Vector2(0x7FFF); + private static readonly Vector2 Min = Vector2.Negate(Max); /// /// Initializes a new instance of the struct. /// - /// The vector containing the component values. - public NormalizedShort2(Vector2 vector) + /// The x-component. + /// The y-component. + public NormalizedShort2(float x, float y) + : this(new Vector2(x, y)) { - this.PackedValue = Pack(vector.X, vector.Y); } /// /// Initializes a new instance of the struct. /// - /// The x-component. - /// The y-component. - public NormalizedShort2(float x, float y) - { - this.PackedValue = Pack(x, y); - } + /// The vector containing the component values. + public NormalizedShort2(Vector2 vector) => this.PackedValue = Pack(vector); /// public uint PackedValue { get; set; } @@ -55,53 +40,39 @@ 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. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(NormalizedShort2 left, NormalizedShort2 right) - { - return left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(NormalizedShort2 left, NormalizedShort2 right) => left.Equals(right); /// /// 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 not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(NormalizedShort2 left, NormalizedShort2 right) - { - return !left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(NormalizedShort2 left, NormalizedShort2 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; scaled -= Vector2.One; - this.PackedValue = Pack(scaled.X, scaled.Y); + this.PackedValue = Pack(scaled); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector2(); @@ -111,146 +82,55 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { - this.PackedValue = Pack(vector.X, vector.Y); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.ToVector2(), 0, 1); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); + var vector2 = new Vector2(vector.X, vector.Y); + this.PackedValue = Pack(vector2); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.ToVector2(), 0, 1); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. /// /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector2 ToVector2() { const float MaxVal = 0x7FFF; @@ -261,61 +141,34 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - public override bool Equals(object obj) - { - return obj is NormalizedShort2 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is NormalizedShort2 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(NormalizedShort2 other) - { - return this.PackedValue.Equals(other.PackedValue); - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(NormalizedShort2 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); /// public override string ToString() { - return this.PackedValue.ToString("X"); + var vector = this.ToVector2(); + return $"NormalizedShort2({vector.X:#0.##}, {vector.Y:#0.##})"; } - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Pack(float x, float y) + [MethodImpl(InliningOptions.ShortMethod)] + private static uint Pack(Vector2 vector) { - const float MaxPos = 0x7FFF; - const float MinNeg = -MaxPos; + vector *= Max; + vector = Vector2.Clamp(vector, Min, Max); - // Clamp the value between min and max values // Round rather than truncate. - uint word2 = (uint)((int)MathF.Round(x * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF); - uint word1 = (uint)(((int)MathF.Round(y * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x10); + uint word2 = (uint)((int)MathF.Round(vector.X) & 0xFFFF); + uint word1 = (uint)(((int)MathF.Round(vector.Y) & 0xFFFF) << 0x10); return word2 | word1; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/NormalizedShort4.cs index 7a74a44349..9717829a24 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort4.cs @@ -15,29 +15,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct NormalizedShort4 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half the maximum byte value. - /// - private static readonly Vector4 Half = new Vector4(127); - - /// - /// The vector value used for rounding. - /// - private static readonly Vector4 Round = new Vector4(.5F); - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the component values. - public NormalizedShort4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + private static readonly Vector4 Max = new Vector4(0x7FFF); + private static readonly Vector4 Min = Vector4.Negate(Max); /// /// Initializes a new instance of the struct. @@ -47,54 +26,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// The z-component. /// The w-component. public NormalizedShort4(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - this.PackedValue = Pack(x, y, z, w); } + /// + /// Initializes a new instance of the struct. + /// + /// The vector containing the component values. + public NormalizedShort4(Vector4 vector) => this.PackedValue = Pack(ref vector); + /// public ulong PackedValue { get; set; } /// /// 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. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(NormalizedShort4 left, NormalizedShort4 right) - { - return left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(NormalizedShort4 left, NormalizedShort4 right) => left.Equals(right); /// /// 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 not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(NormalizedShort4 left, NormalizedShort4 right) - { - return !left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(NormalizedShort4 left, NormalizedShort4 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { vector *= 2F; @@ -103,7 +74,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector4(); @@ -113,14 +84,11 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { const float MaxVal = 0x7FFF; @@ -133,185 +101,68 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override bool Equals(object obj) - { - return obj is NormalizedShort4 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is NormalizedShort4 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(NormalizedShort4 other) - { - return this.PackedValue.Equals(other.PackedValue); - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(NormalizedShort4 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); /// public override string ToString() { - return this.PackedValue.ToString("X"); + var vector = this.ToVector4(); + return $"NormalizedShort4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"; } - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ulong Pack(float x, float y, float z, float w) + [MethodImpl(InliningOptions.ShortMethod)] + private static ulong Pack(ref Vector4 vector) { - const float MaxPos = 0x7FFF; - const float MinNeg = -MaxPos; + vector *= Max; + vector = Vector4.Clamp(vector, Min, Max); - // Clamp the value between min and max values - ulong word4 = ((ulong)MathF.Round(x * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x00; - ulong word3 = ((ulong)MathF.Round(y * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x10; - ulong word2 = ((ulong)MathF.Round(z * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x20; - ulong word1 = ((ulong)MathF.Round(w * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x30; + // Round rather than truncate. + ulong word4 = ((ulong)MathF.Round(vector.X) & 0xFFFF) << 0x00; + ulong word3 = ((ulong)MathF.Round(vector.Y) & 0xFFFF) << 0x10; + ulong word2 = ((ulong)MathF.Round(vector.Z) & 0xFFFF) << 0x20; + ulong word1 = ((ulong)MathF.Round(vector.W) & 0xFFFF) << 0x30; return word4 | word3 | word2 | word1; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; - } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rg32.cs b/src/ImageSharp/PixelFormats/Rg32.cs index e4bed1275b..3375a9753b 100644 --- a/src/ImageSharp/PixelFormats/Rg32.cs +++ b/src/ImageSharp/PixelFormats/Rg32.cs @@ -15,24 +15,23 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct Rg32 : IPixel, IPackedVector { + private static readonly Vector2 Max = new Vector2(ushort.MaxValue); + /// /// Initializes a new instance of the struct. /// /// The x-component /// The y-component public Rg32(float x, float y) + : this(new Vector2(x, y)) { - this.PackedValue = Pack(x, y); } /// /// Initializes a new instance of the struct. /// /// The vector containing the component values. - public Rg32(Vector2 vector) - { - this.PackedValue = Pack(vector.X, vector.Y); - } + public Rg32(Vector2 vector) => this.PackedValue = Pack(vector); /// public uint PackedValue { get; set; } @@ -40,230 +39,111 @@ 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. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rg32 left, Rg32 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rg32 left, Rg32 right) => left.Equals(right); /// /// 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 not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rg32 left, Rg32 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rg32 left, Rg32 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); - /// - /// Expands the packed representation into a . - /// The vector components are typically expanded in least to greatest significance order. - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector2 ToVector2() - { - return new Vector2( - (this.PackedValue & 0xFFFF) / 65535F, - ((this.PackedValue >> 16) & 0xFFFF) / 65535F); - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { - this.PackedValue = Pack(vector.X, vector.Y); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.ToVector2(), 0F, 1F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; + var vector2 = new Vector2(vector.X, vector.Y); + this.PackedValue = Pack(vector2); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.ToVector2(), 0F, 1F); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + /// Expands the packed representation into a . + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public Vector2 ToVector2() => new Vector2(this.PackedValue & 0xFFFF, (this.PackedValue >> 16) & 0xFFFF) / Max; /// - public override bool Equals(object obj) - { - return obj is Rg32 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Rg32 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rg32 other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rg32 other) => this.PackedValue.Equals(other.PackedValue); /// public override string ToString() { - return this.ToVector2().ToString(); + var vector = this.ToVector2(); + return $"Rg32({vector.X:#0.##}, {vector.Y:#0.##})"; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Pack(float x, float y) + [MethodImpl(InliningOptions.ShortMethod)] + private static uint Pack(Vector2 vector) { - return (uint)( - ((int)Math.Round(x.Clamp(0, 1) * 65535F) & 0xFFFF) | - (((int)Math.Round(y.Clamp(0, 1) * 65535F) & 0xFFFF) << 16)); + vector = Vector2.Clamp(vector, Vector2.Zero, Vector2.One) * Max; + return (uint)(((int)Math.Round(vector.X) & 0xFFFF) | (((int)Math.Round(vector.Y) & 0xFFFF) << 16)); } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() => this.ToVector4() * 255F; } -} +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rgb24.cs b/src/ImageSharp/PixelFormats/Rgb24.cs index 4c5aef5438..0b2c39ab5d 100644 --- a/src/ImageSharp/PixelFormats/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/Rgb24.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; using System.Runtime.InteropServices; @@ -42,7 +41,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The red component. /// The green component. /// The blue component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgb24(byte r, byte g, byte b) { this.R = r; @@ -50,39 +49,54 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = b; } + /// + /// Compares two objects for equality. + /// + /// 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. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rgb24 left, Rgb24 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rgb24 left, Rgb24 right) => !left.Equals(right); + /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgb24 other) - { - return this.R == other.R && this.G == other.G && this.B == other.B; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - public override bool Equals(object obj) - { - return obj is Rgb24 other && this.Equals(other); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) { - int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); - return HashHelpers.Combine(hash, this.B.GetHashCode()); + Rgba32 rgba = default; + rgba.PackFromVector4(vector); + this.PackFromRgba32(rgba); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this = Unsafe.As(ref source); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) { this.R = source.R; @@ -91,7 +105,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) { this.R = source.R; @@ -100,74 +114,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - Rgba32 rgba = default; - rgba.PackFromVector4(vector); - this.PackFromRgba32(rgba); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) => dest = this; - - /// - public void ToRgba32(ref Rgba32 dest) - { - dest.Rgb = this; - dest.A = byte.MaxValue; - } - - /// - public void ToArgb32(ref Argb32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; - } - - /// - public void ToBgr24(ref Bgr24 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - } - - /// - public void ToBgra32(ref Bgra32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) { this.R = source.PackedValue; @@ -176,53 +123,57 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) { - var val = (byte)(((source.PackedValue * 255) + 32895) >> 16); - this.R = val; - this.G = val; - this.B = val; + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this = Unsafe.As(ref source); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, byte.MaxValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + public override bool Equals(object obj) => obj is Rgb24 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rgb24 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); /// - public override string ToString() + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() { - return $"({this.R},{this.G},{this.B})"; + int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); + return HashHelpers.Combine(hash, this.B.GetHashCode()); } + + /// + public override string ToString() => $"Rgb24({this.R}, {this.G}, {this.B})"; } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rgb48.cs b/src/ImageSharp/PixelFormats/Rgb48.cs index 7784c49ffb..2ee1be6fe4 100644 --- a/src/ImageSharp/PixelFormats/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/Rgb48.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.PixelFormats [StructLayout(LayoutKind.Sequential)] public struct Rgb48 : IPixel { - private const float Max = 65535F; + private const float Max = ushort.MaxValue; /// /// Gets or sets the red component. @@ -48,29 +48,6 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = b; } - /// - /// Initializes a new instance of the struct. - /// - /// The red component. - /// The green component. - /// The blue component. - public Rgb48(float r, float g, float b) - : this() - { - this.R = (ushort)MathF.Round(r.Clamp(0, 1) * Max); - this.G = (ushort)MathF.Round(g.Clamp(0, 1) * Max); - this.B = (ushort)MathF.Round(b.Clamp(0, 1) * Max); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the components values. - public Rgb48(Vector3 vector) - : this(vector.X, vector.Y, vector.Z) - { - } - /// /// Compares two objects for equality. /// @@ -79,13 +56,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rgb48 left, Rgb48 right) - { - return left.R == right.R - && left.G == right.G - && left.B == right.B; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rgb48 left, Rgb48 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -95,40 +67,22 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rgb48 left, Rgb48 right) - { - return left.R != right.R - || left.G != right.G - || left.B != right.B; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rgb48 left, Rgb48 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.R / Max, this.G / Max, this.B / Max, 1); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; @@ -138,97 +92,43 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R / Max, this.G / Max, this.B / Max, 1F); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) { - this.PackFromVector4(source.ToVector4()); + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) { - this.PackFromVector4(source.ToVector4()); + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this = source.Rgb; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = 255; - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) { - var val = (ushort)(source.PackedValue * 255); - this.R = val; - this.G = val; - this.B = val; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) - { - dest.PackFromRgb48(this); + ushort rgb = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) { this.R = source.PackedValue; @@ -236,49 +136,41 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = source.PackedValue; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) { - dest.PackFromRgb48(this); + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this = source; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest = this; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() { - dest.Rgb = this; - dest.A = ushort.MaxValue; + byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R); + byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G); + byte b = ImageMaths.DownScaleFrom16BitTo8Bit(this.B); + return new Rgba32(r, g, b, byte.MaxValue); } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this = source; + /// - public override bool Equals(object obj) - { - return obj is Rgb48 rgb48 && this.Equals(rgb48); - } + public override bool Equals(object obj) => obj is Rgb48 rgb48 && this.Equals(rgb48); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgb48 other) - { - return this.R == other.R - && this.G == other.G - && this.B == other.B; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rgb48 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); /// - public override string ToString() => this.ToVector4().ToString(); + public override string ToString() => $"Rgb48({this.R}, {this.G}, {this.B})"; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() { return HashHelpers.Combine( diff --git a/src/ImageSharp/PixelFormats/Rgba1010102.cs b/src/ImageSharp/PixelFormats/Rgba1010102.cs index 6dd5f7b544..8bcf34f309 100644 --- a/src/ImageSharp/PixelFormats/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/Rgba1010102.cs @@ -16,6 +16,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct Rgba1010102 : IPixel, IPackedVector { + private static readonly Vector4 Multiplier = new Vector4(1023F, 1023F, 1023F, 3F); + /// /// Initializes a new instance of the struct. /// @@ -24,18 +26,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// The z-component /// The w-component public Rgba1010102(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - this.PackedValue = Pack(x, y, z, w); } /// /// Initializes a new instance of the struct. /// /// The vector containing the component values. - public Rgba1010102(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + public Rgba1010102(Vector4 vector) => this.PackedValue = Pack(ref vector); /// public uint PackedValue { get; set; } @@ -43,222 +42,107 @@ 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. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rgba1010102 left, Rgba1010102 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rgba1010102 left, Rgba1010102 right) => left.Equals(right); /// /// 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 not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rgba1010102 left, Rgba1010102 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rgba1010102 left, Rgba1010102 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4( - ((this.PackedValue >> 0) & 0x03FF) / 1023F, - ((this.PackedValue >> 10) & 0x03FF) / 1023F, - ((this.PackedValue >> 20) & 0x03FF) / 1023F, - ((this.PackedValue >> 30) & 0x03) / 3F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); + return new Vector4( + (this.PackedValue >> 0) & 0x03FF, + (this.PackedValue >> 10) & 0x03FF, + (this.PackedValue >> 20) & 0x03FF, + (this.PackedValue >> 30) & 0x03) / Multiplier; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override bool Equals(object obj) - { - return obj is Rgba1010102 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Rgba1010102 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgba1010102 other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rgba1010102 other) => this.PackedValue == other.PackedValue; /// - public override string ToString() - { - return this.ToVector4().ToString(); - } + public override string ToString() => this.ToVector4().ToString(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Pack(float x, float y, float z, float w) + [MethodImpl(InliningOptions.ShortMethod)] + private static uint Pack(ref Vector4 vector) { + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Multiplier; + return (uint)( - (((int)Math.Round(x.Clamp(0, 1) * 1023F) & 0x03FF) << 0) | - (((int)Math.Round(y.Clamp(0, 1) * 1023F) & 0x03FF) << 10) | - (((int)Math.Round(z.Clamp(0, 1) * 1023F) & 0x03FF) << 20) | - (((int)Math.Round(w.Clamp(0, 1) * 3F) & 0x03) << 30)); + (((int)Math.Round(vector.X) & 0x03FF) << 0) + | (((int)Math.Round(vector.Y) & 0x03FF) << 10) + | (((int)Math.Round(vector.Z) & 0x03FF) << 20) + | (((int)Math.Round(vector.W) & 0x03) << 30)); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index aab9fad928..e92da02668 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The red component. /// The green component. /// The blue component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(byte r, byte g, byte b) { this.R = r; @@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(byte r, byte g, byte b, byte a) { this.R = r; @@ -109,12 +109,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] 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. @@ -122,12 +119,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components for the packed vector. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(Vector3 vector) - : this() - { - this.Pack(ref vector); - } + : this() => this.Pack(ref vector); /// /// Initializes a new instance of the struct. @@ -135,12 +129,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components for the packed vector. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(Vector4 vector) - : this() - { - this = PackNew(ref vector); - } + : this() => this = PackNew(ref vector); /// /// Initializes a new instance of the struct. @@ -148,22 +139,19 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The packed value. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(uint packed) - : this() - { - this.Rgba = packed; - } + : this() => this.Rgba = packed; /// /// Gets or sets the packed representation of the Rgba32 struct. /// public uint Rgba { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => Unsafe.As(ref this); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; } @@ -172,10 +160,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// public Rgb24 Rgb { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => Unsafe.As(ref this); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; } @@ -184,10 +172,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// public Bgr24 Bgr { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => new Bgr24(this.R, this.G, this.B); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set { this.R = value.R; @@ -199,30 +187,23 @@ namespace SixLabors.ImageSharp.PixelFormats /// public uint PackedValue { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => this.Rgba; - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => this.Rgba = value; } /// /// 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. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rgba32 left, Rgba32 right) - { - return left.Rgba == right.Rgba; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rgba32 left, Rgba32 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -232,11 +213,8 @@ 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; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rgba32 left, Rgba32 right) => !left.Equals(right); /// /// Creates a new instance of the struct. @@ -248,23 +226,29 @@ 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; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; + + /// + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) { this.R = source.R; @@ -274,7 +258,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) { this.R = source.R; @@ -283,213 +267,85 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = source.A; } - /// - /// Converts the value of this instance to a hexadecimal string. - /// - /// A hexadecimal string representation of the value. - public string ToHex() - { - uint hexOrder = (uint)(this.A << 0 | this.B << 8 | this.G << 16 | this.R << 24); - return hexOrder.ToString("X8"); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest = Unsafe.As(ref this); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - dest = this; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) { this.R = source.PackedValue; this.G = source.PackedValue; this.B = source.PackedValue; - this.A = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) - { - dest.PackFromRgba32(this); + this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) { - var val = (byte)(((source.PackedValue * 255) + 32895) >> 16); - this.R = val; - this.G = val; - this.B = val; - this.A = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) - { - dest.PackFromRgba32(this); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.Pack(ref vector); + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; + this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; - } - - /// - /// Gets the value of this struct as . - /// Useful for changing the component order. - /// - /// A value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Bgra32 ToBgra32() => new Bgra32(this.R, this.G, this.B, this.A); - - /// - /// Gets the value of this struct as . - /// Useful for changing the component order. - /// - /// A value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Argb32 ToArgb32() => new Argb32(this.R, this.G, this.B, this.A); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this = source; - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] + /// + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32 ToRgba32() => this; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) { - // Taken from libpng pngtran.c line: 2419 - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); - this.A = (byte)(((source.A * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); + this.A = ImageMaths.DownScaleFrom16BitTo8Bit(source.A); } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override bool Equals(object obj) + /// + /// Converts the value of this instance to a hexadecimal string. + /// + /// A hexadecimal string representation of the value. + public string ToHex() { - return obj is Rgba32 rgba32 && this.Equals(rgba32); + uint hexOrder = (uint)(this.A << 0 | this.B << 8 | this.G << 16 | this.R << 24); + return hexOrder.ToString("X8"); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgba32 other) - { - return this.Rgba == other.Rgba; - } + public override bool Equals(object obj) => obj is Rgba32 rgba32 && this.Equals(rgba32); /// - public override string ToString() - { - return $"({this.R},{this.G},{this.B},{this.A})"; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rgba32 other) => this.Rgba.Equals(other.Rgba); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() => this.Rgba.GetHashCode(); + public override string ToString() => $"Rgba32({this.R}, {this.G}, {this.B}, {this.A})"; - /// - /// Gets the representation without normalizing to [0, 1] - /// - /// A of values in [0, 255] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Vector4 ToByteScaledVector4() - { - return new Vector4(this.R, this.G, this.B, this.A); - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.Rgba.GetHashCode(); /// /// Packs a into a color returning a new instance as a result. /// /// The vector containing the values to pack. /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static Rgba32 PackNew(ref Vector4 vector) { vector *= MaxBytes; @@ -506,7 +362,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The y-component /// The z-component /// The w-component - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(float x, float y, float z, float w) { var value = new Vector4(x, y, z, w); @@ -517,10 +373,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// Packs a into a uint. /// /// The vector containing the values to pack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(ref Vector3 vector) { - var value = new Vector4(vector, 1); + var value = new Vector4(vector, 1F); this.Pack(ref value); } @@ -528,7 +384,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Packs a into a color. /// /// The vector containing the values to pack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(ref Vector4 vector) { vector *= MaxBytes; diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/Rgba64.cs index 5c3187856e..623f7051af 100644 --- a/src/ImageSharp/PixelFormats/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/Rgba64.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.PixelFormats [StructLayout(LayoutKind.Sequential)] public struct Rgba64 : IPixel, IPackedVector { - private const float Max = 65535F; + private const float Max = ushort.MaxValue; /// /// Gets or sets the red component. @@ -47,7 +47,6 @@ namespace SixLabors.ImageSharp.PixelFormats /// The blue component. /// The alpha component. public Rgba64(ushort r, ushort g, ushort b, ushort a) - : this() { this.R = r; this.G = g; @@ -55,126 +54,63 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = a; } - /// - /// Initializes a new instance of the struct. - /// - /// The red component. - /// The green component. - /// The blue component. - /// The alpha component. - public Rgba64(float r, float g, float b, float a) - : this() - { - this.R = (ushort)MathF.Round(r.Clamp(0, 1) * Max); - this.G = (ushort)MathF.Round(g.Clamp(0, 1) * Max); - this.B = (ushort)MathF.Round(b.Clamp(0, 1) * Max); - this.A = (ushort)MathF.Round(a.Clamp(0, 1) * Max); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the components values. - public Rgba64(Vector4 vector) - : this(vector.X, vector.Y, vector.Z, vector.W) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The packed value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Rgba64(ulong packed) - : this() - { - this.PackedValue = packed; - } - /// /// Gets or sets the RGB components of this struct as /// public Rgb48 Rgb { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => Unsafe.As(ref this); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; } /// public ulong PackedValue { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => Unsafe.As(ref this); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; } /// /// 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. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rgba64 left, Rgba64 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rgba64 left, Rgba64 right) => left.PackedValue == right.PackedValue; /// /// 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 not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rgba64 left, Rgba64 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rgba64 left, Rgba64 right) => left.PackedValue != right.PackedValue; /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.R, this.G, this.B, this.A) / Max; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; @@ -185,145 +121,95 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / Max; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) { - this.PackFromVector4(source.ToVector4()); + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this = source; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - // Taken from libpng pngtran.c line: 2419 - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = (byte)(((this.A * 255) + 32895) >> 16); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) { - this.Rgb = source; + ushort rgb = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; this.A = ushort.MaxValue; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest = this.Rgb; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest = this; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = (byte)(((this.A * 255) + 32895) >> 16); + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + this.A = ushort.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = (byte)(((this.A * 255) + 32895) >> 16); + byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R); + byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G); + byte b = ImageMaths.DownScaleFrom16BitTo8Bit(this.B); + byte a = ImageMaths.DownScaleFrom16BitTo8Bit(this.A); + return new Rgba32(r, g, b, a); } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromGray8(Gray8 source) - { - ushort x = (ushort)(source.PackedValue * 255); - this.R = x; - this.G = x; - this.B = x; - this.A = ushort.MaxValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromGray16(Gray16 source) + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) { - this.R = source.PackedValue; - this.G = source.PackedValue; - this.B = source.PackedValue; + this.Rgb = source; this.A = ushort.MaxValue; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba64(Rgba64 source) => this = source; /// - public override bool Equals(object obj) - { - return obj is Rgba64 rgba64 && this.Equals(rgba64); - } + public override bool Equals(object obj) => obj is Rgba64 rgba64 && this.Equals(rgba64); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgba64 other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rgba64 other) => this.PackedValue.Equals(other.PackedValue); /// - public override string ToString() - { - return $"({this.R},{this.G},{this.B},{this.A})"; - } + public override string ToString() => $"Rgba64({this.R}, {this.G}, {this.B}, {this.A})"; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/RgbaVector.cs b/src/ImageSharp/PixelFormats/RgbaVector.cs index 3ab45a66ef..5ca0ce406f 100644 --- a/src/ImageSharp/PixelFormats/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/RgbaVector.cs @@ -1,9 +1,9 @@ // 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.PixelFormats { @@ -18,36 +18,32 @@ namespace SixLabors.ImageSharp.PixelFormats /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, /// as it avoids the need to create new values for modification operations. /// + [StructLayout(LayoutKind.Sequential)] public partial struct RgbaVector : IPixel { /// - /// The maximum byte value. + /// Gets or sets the red component. /// - private static readonly Vector4 MaxBytes = new Vector4(255); + public float R; /// - /// The half vector value. + /// Gets or sets the green component. /// - private static readonly Vector4 Half = new Vector4(0.5F); + public float G; /// - /// The backing vector for SIMD support. + /// Gets or sets the blue component. /// - private Vector4 backingVector; + public float B; /// - /// Initializes a new instance of the struct. + /// Gets or sets the alpha component. /// - /// The red component. - /// The green component. - /// The blue component. - /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public RgbaVector(byte r, byte g, byte b, byte a = 255) - : this() - { - this.backingVector = new Vector4(r, g, b, a) / MaxBytes; - } + public float A; + + private const float MaxBytes = byte.MaxValue; + private static readonly Vector4 Max = new Vector4(MaxBytes); + private static readonly Vector4 Half = new Vector4(0.5F); /// /// Initializes a new instance of the struct. @@ -56,128 +52,25 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public RgbaVector(float r, float g, float b, float a = 1) - : this() - { - this.backingVector = new Vector4(r, g, b, a); - } - - /// - /// Initializes a new instance of the struct. - /// - /// - /// The vector containing the components for the packed vector. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public RgbaVector(Vector3 vector) - : this() - { - this.backingVector = new Vector4(vector, 1); - } - - /// - /// Initializes a new instance of the struct. - /// - /// - /// The vector containing the components for the packed vector. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public RgbaVector(Vector4 vector) - : this() - { - this.backingVector = vector; - } - - /// - /// Gets or sets the red component. - /// - public float R - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return this.backingVector.X; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - this.backingVector.X = value; - } - } - - /// - /// Gets or sets the green component. - /// - public float G - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return this.backingVector.Y; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - this.backingVector.Y = value; - } - } - - /// - /// Gets or sets the blue component. - /// - public float B { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return this.backingVector.Z; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - this.backingVector.Z = value; - } - } - - /// - /// Gets or sets the alpha component. - /// - public float A - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return this.backingVector.W; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - this.backingVector.W = value; - } + this.R = r; + this.G = g; + this.B = b; + this.A = a; } /// /// 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. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(RgbaVector left, RgbaVector right) - { - return left.backingVector == right.backingVector; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(RgbaVector left, RgbaVector right) => left.Equals(right); /// /// Compares two objects for equality. @@ -187,11 +80,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(RgbaVector left, RgbaVector right) - { - return left.backingVector != right.backingVector; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(RgbaVector left, RgbaVector right) => !left.Equals(right); /// /// Creates a new instance of the struct. @@ -203,190 +93,103 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The . /// - public static RgbaVector FromHex(string hex) - { - return ColorBuilder.FromHex(hex); - } + public static RgbaVector FromHex(string hex) => ColorBuilder.FromHex(hex); /// - public PixelOperations CreatePixelOperations() => new RgbaVector.PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.backingVector = source.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.backingVector = source.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.backingVector = source.ToVector4(); - } - - /// - /// Converts the value of this instance to a hexadecimal string. - /// - /// A hexadecimal string representation of the value. - public string ToHex() - { - // Hex is RRGGBBAA - Vector4 vector = this.backingVector * MaxBytes; - vector += Half; - uint hexOrder = (uint)((byte)vector.W | (byte)vector.Z << 8 | (byte)vector.Y << 16 | (byte)vector.X << 24); - return hexOrder.ToString("X8"); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); + this.R = vector.X; + this.G = vector.Y; + this.B = vector.Z; + this.A = vector.W; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) + /// + /// Converts the value of this instance to a hexadecimal string. + /// + /// A hexadecimal string representation of the value. + public string ToHex() { - this.backingVector = vector; + // Hex is RRGGBBAA + Vector4 vector = this.ToVector4() * Max; + vector += Half; + uint hexOrder = (uint)((byte)vector.W | (byte)vector.Z << 8 | (byte)vector.Y << 16 | (byte)vector.X << 24); + return hexOrder.ToString("X8"); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return this.backingVector; - } + public override bool Equals(object obj) => obj is RgbaVector other && this.Equals(other); /// - public override bool Equals(object obj) - { - return obj is RgbaVector other && this.Equals(other); - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(RgbaVector other) => + this.R.Equals(other.R) + && this.G.Equals(other.G) + && this.B.Equals(other.B) + && this.A.Equals(other.A); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(RgbaVector other) - { - return this.backingVector == other.backingVector; - } - - /// - /// Gets a string representation of the packed vector. - /// - /// A string representation of the packed vector. public override string ToString() { - return this.ToVector4().ToString(); + var vector = this.ToVector4(); + return $"RgbaVector({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##}, {this.A:#0.##})"; } /// public override int GetHashCode() { - return this.backingVector.GetHashCode(); + int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); + hash = HashHelpers.Combine(hash, this.B.GetHashCode()); + return HashHelpers.Combine(hash, this.A.GetHashCode()); } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() => Vector4.Clamp(this.backingVector, Vector4.Zero, Vector4.One) * MaxBytes; } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Short2.cs b/src/ImageSharp/PixelFormats/Short2.cs index 331c5fb208..24430a5d9f 100644 --- a/src/ImageSharp/PixelFormats/Short2.cs +++ b/src/ImageSharp/PixelFormats/Short2.cs @@ -15,39 +15,30 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct Short2 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector2 MaxBytes = new Vector2(255); + // Largest two byte positive number 0xFFFF >> 1; + private const float MaxPos = 0x7FFF; - /// - /// The half the maximum byte value. - /// - private static readonly Vector2 Half = new Vector2(127); + // Two's complement + private const float MinNeg = ~(int)MaxPos; - /// - /// The vector value used for rounding. - /// - private static readonly Vector2 Round = new Vector2(.5F); + private static readonly Vector2 Max = new Vector2(MaxPos); + private static readonly Vector2 Min = new Vector2(MinNeg); /// /// Initializes a new instance of the struct. /// - /// The vector containing the component values. - public Short2(Vector2 vector) + /// The x-component. + /// The y-component. + public Short2(float x, float y) + : this(new Vector2(x, y)) { - this.PackedValue = Pack(vector.X, vector.Y); } /// /// Initializes a new instance of the struct. /// - /// The x-component. - /// The y-component. - public Short2(float x, float y) - { - this.PackedValue = Pack(x, y); - } + /// The vector containing the component values. + public Short2(Vector2 vector) => this.PackedValue = Pack(vector); /// public uint PackedValue { get; set; } @@ -55,53 +46,39 @@ 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. + /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Short2 left, Short2 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Short2 left, Short2 right) => left.Equals(right); /// /// 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 not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Short2 left, Short2 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Short2 left, Short2 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { Vector2 scaled = new Vector2(vector.X, vector.Y) * 65534F; scaled -= new Vector2(32767F); - this.PackedValue = Pack(scaled.X, scaled.Y); + this.PackedValue = Pack(scaled); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector2(); @@ -111,198 +88,83 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { - this.PackedValue = Pack(vector.X, vector.Y); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10), 0, 1); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - Vector2 vector = new Vector2(source.R, source.G) / 255; - vector *= 65534; - vector -= new Vector2(32767); - this.PackedValue = Pack(vector.X, vector.Y); + var vector2 = new Vector2(vector.X, vector.Y); + this.PackedValue = Pack(vector2); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - Vector2 vector = new Vector2(source.R, source.G) / 255; - vector *= 65534; - vector -= new Vector2(32767); - this.PackedValue = Pack(vector.X, vector.Y); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10), 0, 1); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - Vector2 vector = new Vector2(source.R, source.G) / 255; - vector *= 65534; - vector -= new Vector2(32767); - this.PackedValue = Pack(vector.X, vector.Y); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector2 vector = this.ToByteScaledVector2(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector2 vector = this.ToByteScaledVector2(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector2 vector = this.ToByteScaledVector2(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector2 vector = this.ToByteScaledVector2(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector2 vector = this.ToByteScaledVector2(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + /// + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + /// + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. /// /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector2 ToVector2() - { - return new Vector2((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10)); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector2 ToVector2() => new Vector2((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10)); /// - public override bool Equals(object obj) - { - return obj is Short2 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Short2 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Short2 other) - { - return this == other; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Short2 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); /// public override string ToString() { - return this.PackedValue.ToString("x8"); + var vector = this.ToVector2(); + return $"Short2({vector.X:#0.##}, {vector.Y:#0.##})"; } - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Pack(float x, float y) + [MethodImpl(InliningOptions.ShortMethod)] + private static uint Pack(Vector2 vector) { - // Largest two byte positive number 0xFFFF >> 1; - const float MaxPos = 0x7FFF; - const float MinNeg = ~(int)MaxPos; - - // Clamp the value between min and max values - uint word2 = (uint)Math.Round(x.Clamp(MinNeg, MaxPos)) & 0xFFFF; - uint word1 = ((uint)Math.Round(y.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x10; + vector = Vector2.Clamp(vector, Min, Max); + uint word2 = (uint)Math.Round(vector.X) & 0xFFFF; + uint word1 = ((uint)Math.Round(vector.Y) & 0xFFFF) << 0x10; return word2 | word1; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector2 ToByteScaledVector2() - { - var vector = this.ToVector2(); - vector /= 65534; - vector *= 255; - vector += Half; - vector += Round; - vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes); - return vector; - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Short4.cs b/src/ImageSharp/PixelFormats/Short4.cs index 4a3d89ad8b..4925137470 100644 --- a/src/ImageSharp/PixelFormats/Short4.cs +++ b/src/ImageSharp/PixelFormats/Short4.cs @@ -15,29 +15,14 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct Short4 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); + // Largest two byte positive number 0xFFFF >> 1; + private const float MaxPos = 0x7FFF; - /// - /// The half the maximum byte value. - /// - private static readonly Vector4 Half = new Vector4(127); + // Two's complement + private const float MinNeg = ~(int)MaxPos; - /// - /// The vector value used for rounding. - /// - private static readonly Vector4 Round = new Vector4(.5F); - - /// - /// Initializes a new instance of the struct. - /// - /// A vector containing the initial values for the components. - public Short4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + private static readonly Vector4 Max = new Vector4(MaxPos); + private static readonly Vector4 Min = new Vector4(MinNeg); /// /// Initializes a new instance of the struct. @@ -47,54 +32,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// The z-component. /// The w-component. public Short4(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - this.PackedValue = Pack(x, y, z, w); } + /// + /// Initializes a new instance of the struct. + /// + /// A vector containing the initial values for the components. + public Short4(Vector4 vector) => this.PackedValue = Pack(ref vector); + /// public ulong PackedValue { get; set; } /// /// 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 not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Short4 left, Short4 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Short4 left, Short4 right) => left.Equals(right); /// /// 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 not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Short4 left, Short4 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Short4 left, Short4 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { vector *= 65534F; @@ -103,7 +80,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector4(); @@ -113,14 +90,11 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { return new Vector4( @@ -131,184 +105,70 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - var vector = source.ToVector4(); - vector *= 65534; - vector -= new Vector4(32767); - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - var vector = source.ToVector4(); - vector *= 65534; - vector -= new Vector4(32767); - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - var vector = source.ToVector4(); - vector *= 65534; - vector -= new Vector4(32767); - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromVector4(this.ToVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromVector4(this.ToVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override bool Equals(object obj) - { - return obj is Short4 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Short4 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Short4 other) - { - return this == other; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Short4 other) => this.PackedValue.Equals(other); /// /// Gets the hash code for the current instance. /// /// Hash code for the instance. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - /// - /// Returns a string representation of the current instance. - /// - /// String that represents the object. + /// public override string ToString() { - return this.PackedValue.ToString("x16"); + var vector = this.ToVector4(); + return $"Short4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"; } - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ulong Pack(float x, float y, float z, float w) + [MethodImpl(InliningOptions.ShortMethod)] + private static ulong Pack(ref Vector4 vector) { - // Largest two byte positive number 0xFFFF >> 1; - const float MaxPos = 0x7FFF; - - // Two's complement - const float MinNeg = ~(int)MaxPos; + vector = Vector4.Clamp(vector, Min, Max); // Clamp the value between min and max values - ulong word4 = ((ulong)Math.Round(x.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x00; - ulong word3 = ((ulong)Math.Round(y.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x10; - ulong word2 = ((ulong)Math.Round(z.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x20; - ulong word1 = ((ulong)Math.Round(w.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x30; + ulong word4 = ((ulong)Math.Round(vector.X) & 0xFFFF) << 0x00; + ulong word3 = ((ulong)Math.Round(vector.Y) & 0xFFFF) << 0x10; + ulong word2 = ((ulong)Math.Round(vector.Z) & 0xFFFF) << 0x20; + ulong word1 = ((ulong)Math.Round(vector.W) & 0xFFFF) << 0x30; return word4 | word3 | word2 | word1; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector /= 65534; - vector *= 255; - vector += Half; - vector += Round; - return Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs index 5041dcf5ac..b338ff446e 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs @@ -76,8 +76,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - float threshold = this.Threshold * 255F; - Rgba32 rgba = default; + byte threshold = (byte)MathF.Round(this.Threshold * 255F); bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); @@ -89,10 +88,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // Collect the values before looping so we can reduce our calculation count for identical sibling pixels TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; - sourcePixel.ToRgba32(ref rgba); + var rgba = sourcePixel.ToRgba32(); // 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); + byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); for (int y = startY; y < endY; y++) { @@ -106,8 +105,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // rather than calculating it again. This is an inexpensive optimization. if (!previousPixel.Equals(sourcePixel)) { - sourcePixel.ToRgba32(ref rgba); - luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + rgba = sourcePixel.ToRgba32(); + luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer previousPixel = sourcePixel; diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs index 048af82619..0b28a1574b 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs @@ -56,7 +56,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - Rgba32 rgba = default; bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); @@ -68,10 +67,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // Collect the values before looping so we can reduce our calculation count for identical sibling pixels TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; - sourcePixel.ToRgba32(ref rgba); + var rgba = sourcePixel.ToRgba32(); // 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); + byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); for (int y = startY; y < endY; y++) { @@ -85,8 +84,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // rather than calculating it again. This is an inexpensive optimization. if (!previousPixel.Equals(sourcePixel)) { - sourcePixel.ToRgba32(ref rgba); - luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + rgba = sourcePixel.ToRgba32(); + luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer previousPixel = sourcePixel; diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs index 60754b3bf2..03b7f73e94 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs @@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization Rectangle sourceRectangle, Configuration configuration) { - float threshold = this.Threshold * 255F; + byte threshold = (byte)MathF.Round(this.Threshold * 255F); TPixel upper = this.UpperColor; TPixel lower = this.LowerColor; @@ -83,17 +83,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization for (int y = rows.Min; y < rows.Max; y++) { 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); + var rgba = color.ToRgba32(); // 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); + byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); color = luminance >= threshold ? upper : lower; } } diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs index 8e2b2a5a82..b60322799a 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs @@ -4,7 +4,6 @@ using System; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors.Dithering; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Dithering @@ -64,8 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - float threshold = this.Threshold * 255F; - Rgba32 rgba = default; + byte threshold = (byte)MathF.Round(this.Threshold * 255F); bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); @@ -78,10 +76,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; PixelPair pair = this.GetClosestPixelPair(ref sourcePixel); - sourcePixel.ToRgba32(ref rgba); + var rgba = sourcePixel.ToRgba32(); // 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); + byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); for (int y = startY; y < endY; y++) { @@ -103,8 +101,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering continue; } - sourcePixel.ToRgba32(ref rgba); - luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + rgba = sourcePixel.ToRgba32(); + luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer previousPixel = sourcePixel; diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs index b5e2eebc2b..149c7170ac 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs @@ -4,7 +4,6 @@ using System; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors.Dithering; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Dithering @@ -32,10 +31,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// The ordered ditherer. /// The palette to select substitute colors from. public OrderedDitherPaletteProcessor(IOrderedDither dither, TPixel[] palette) - : base(palette) - { - this.Dither = dither ?? throw new ArgumentNullException(nameof(dither)); - } + : base(palette) => this.Dither = dither ?? throw new ArgumentNullException(nameof(dither)); /// /// Gets the ditherer. @@ -45,7 +41,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - Rgba32 rgba = default; bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); @@ -58,10 +53,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; PixelPair pair = this.GetClosestPixelPair(ref sourcePixel); - sourcePixel.ToRgba32(ref rgba); + var rgba = sourcePixel.ToRgba32(); // 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); + byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); for (int y = startY; y < endY; y++) { @@ -83,8 +78,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering continue; } - sourcePixel.ToRgba32(ref rgba); - luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + rgba = sourcePixel.ToRgba32(); + luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer previousPixel = sourcePixel; diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs index 39546d63f7..552aa8af82 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs @@ -73,14 +73,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization 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); // Add the color to the Octree - this.octree.AddColor(ref pixel, ref rgba); + this.octree.AddColor(ref pixel); } } } @@ -97,9 +95,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization // pass of the algorithm by avoiding transforming rows of identical color. TPixel sourcePixel = source[0, 0]; TPixel previousPixel = sourcePixel; - Rgba32 rgba = default; this.transparentIndex = this.GetTransparentIndex(); - byte pixelValue = this.QuantizePixel(ref sourcePixel, ref rgba); + byte pixelValue = this.QuantizePixel(ref sourcePixel); TPixel transformedPixel = palette[pixelValue]; for (int y = 0; y < height; y++) @@ -117,7 +114,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (!previousPixel.Equals(sourcePixel)) { // Quantize the pixel - pixelValue = this.QuantizePixel(ref sourcePixel, ref rgba); + pixelValue = this.QuantizePixel(ref sourcePixel); // And setup the previous pointer previousPixel = sourcePixel; @@ -146,10 +143,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Process the pixel in the second pass of the algorithm. /// /// The pixel to quantize. - /// The color to compare against. /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] - private byte QuantizePixel(ref TPixel pixel, ref Rgba32 rgba) + private byte QuantizePixel(ref TPixel pixel) { if (this.Dither) { @@ -158,13 +154,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization return this.GetClosestPixel(ref pixel); } - pixel.ToRgba32(ref rgba); + var rgba = pixel.ToRgba32(); if (rgba.Equals(default)) { return this.transparentIndex; } - return (byte)this.octree.GetPaletteIndex(ref pixel, ref rgba); + return (byte)this.octree.GetPaletteIndex(ref pixel); } /// @@ -239,8 +235,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Add a given color value to the Octree /// /// The pixel data. - /// The color. - public void AddColor(ref TPixel pixel, ref Rgba32 rgba) + public void AddColor(ref TPixel pixel) { // Check if this request is for the same color as the last if (this.previousColor.Equals(pixel)) @@ -250,18 +245,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (this.previousNode is null) { this.previousColor = pixel; - this.root.AddColor(ref pixel, this.maxColorBits, 0, this, ref rgba); + this.root.AddColor(ref pixel, this.maxColorBits, 0, this); } else { // Just update the previous node - this.previousNode.Increment(ref pixel, ref rgba); + this.previousNode.Increment(ref pixel); } } else { this.previousColor = pixel; - this.root.AddColor(ref pixel, this.maxColorBits, 0, this, ref rgba); + this.root.AddColor(ref pixel, this.maxColorBits, 0, this); } } @@ -294,12 +289,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Get the palette index for the passed color /// /// The pixel data. - /// The color to map to. /// /// The . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int GetPaletteIndex(ref TPixel pixel, ref Rgba32 rgba) => this.root.GetPaletteIndex(ref pixel, 0, ref rgba); + public int GetPaletteIndex(ref TPixel pixel) => this.root.GetPaletteIndex(ref pixel, 0); /// /// Keep track of the previous node that was quantized @@ -426,13 +420,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The number of significant color bits /// The level in the tree /// The tree to which this node belongs - /// The color to map to. - public void AddColor(ref TPixel pixel, int colorBits, int level, Octree octree, ref Rgba32 rgba) + public void AddColor(ref TPixel pixel, int colorBits, int level, Octree octree) { // Update the color information if this is a leaf if (this.leaf) { - this.Increment(ref pixel, ref rgba); + this.Increment(ref pixel); // Setup the previous node octree.TrackPrevious(this); @@ -441,7 +434,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { // Go to the next level down in the tree int shift = 7 - level; - pixel.ToRgba32(ref rgba); + var rgba = pixel.ToRgba32(); int index = ((rgba.B & Mask[level]) >> (shift - 2)) | ((rgba.G & Mask[level]) >> (shift - 1)) @@ -456,7 +449,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } // Add the color to the child node - child.AddColor(ref pixel, colorBits, level + 1, octree, ref rgba); + child.AddColor(ref pixel, colorBits, level + 1, octree); } } @@ -525,19 +518,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The pixel data. /// The level. - /// The color to map to. /// /// The representing the index of the pixel in the palette. /// [MethodImpl(MethodImplOptions.NoInlining)] - public int GetPaletteIndex(ref TPixel pixel, int level, ref Rgba32 rgba) + public int GetPaletteIndex(ref TPixel pixel, int level) { int index = this.paletteIndex; if (!this.leaf) { int shift = 7 - level; - pixel.ToRgba32(ref rgba); + var rgba = pixel.ToRgba32(); int pixelIndex = ((rgba.B & Mask[level]) >> (shift - 2)) | ((rgba.G & Mask[level]) >> (shift - 1)) @@ -546,7 +538,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization OctreeNode child = this.children[pixelIndex]; if (child != null) { - index = child.GetPaletteIndex(ref pixel, level + 1, ref rgba); + index = child.GetPaletteIndex(ref pixel, level + 1); } else { @@ -561,11 +553,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Increment the pixel count and add to the color information /// /// The pixel to add. - /// The color to map to. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Increment(ref TPixel pixel, ref Rgba32 rgba) + public void Increment(ref TPixel pixel) { - pixel.ToRgba32(ref rgba); + var rgba = pixel.ToRgba32(); this.pixelCount++; this.red += rgba.R; this.green += rgba.G; diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 13bc057da8..f3b5da3202 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -442,33 +442,36 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization // Build up the 3-D color histogram // Loop through each row - for (int y = 0; y < height; y++) + using (IMemoryOwner rgbaBuffer = source.MemoryAllocator.Allocate(source.Width)) { - 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++) + for (int y = 0; y < height; y++) { - ref TPixel pixel = ref Unsafe.Add(ref scanBaseRef, x); - pixel.ToRgba32(ref rgba); + Span row = source.GetPixelRowSpan(y); + Span rgbaSpan = rgbaBuffer.GetSpan(); + PixelOperations.Instance.ToRgba32(row, rgbaSpan, source.Width); + ref Rgba32 scanBaseRef = ref MemoryMarshal.GetReference(rgbaSpan); + + // And loop through each column + for (int x = 0; x < width; x++) + { + ref Rgba32 rgba = ref Unsafe.Add(ref scanBaseRef, x); - 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 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); + 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; + 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); + var vector = new Vector4(rgba.R, rgba.G, rgba.B, rgba.A); + m2Span[index] += Vector4.Dot(vector, vector); + } } } } @@ -876,8 +879,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } // Expected order r->g->b->a - Rgba32 rgba = default; - pixel.ToRgba32(ref rgba); + var rgba = pixel.ToRgba32(); int r = rgba.R >> (8 - IndexBits); int g = rgba.G >> (8 - IndexBits); diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs index 4e9c6d10a6..f96023f000 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs @@ -4,10 +4,7 @@ // ReSharper disable InconsistentNaming using System.Buffers; -using System; - using BenchmarkDotNet.Attributes; - using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -38,35 +35,10 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark(Baseline = true)] - public void PerElement() - { - Span s = this.source.GetSpan(); - Span d = this.destination.GetSpan(); - - var rgb = default(Rgb24); - - for (int i = 0; i < this.Count; i++) - { - TPixel c = s[i]; - int i3 = i * 3; - c.ToRgb24(ref rgb); - d[i3] = rgb.R; - d[i3 + 1] = rgb.G; - d[i3 + 2] = rgb.B; - } - } + public void CommonBulk() => new PixelOperations().ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); [Benchmark] - public void CommonBulk() - { - new PixelOperations().ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } - - [Benchmark] - public void OptimizedBulk() - { - PixelOperations.Instance.ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } + public void OptimizedBulk() => PixelOperations.Instance.ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } public class ToXyz_Rgba32 : ToXyz diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs index 8166c8f465..740287e85a 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs @@ -42,13 +42,11 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk Span s = this.source.GetSpan(); Span d = this.destination.GetSpan(); - var rgba = default(Rgba32); - for (int i = 0; i < this.Count; i++) { TPixel c = s[i]; int i4 = i * 4; - c.ToRgba32(ref rgba); + var rgba = c.ToRgba32(); d[i4] = rgba.R; d[i4 + 1] = rgba.G; d[i4 + 2] = rgba.B; @@ -57,16 +55,10 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark] - public void CommonBulk() - { - new PixelOperations().ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } + public void CommonBulk() => new PixelOperations().ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); [Benchmark] - public void OptimizedBulk() - { - PixelOperations.Instance.ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } + public void OptimizedBulk() => PixelOperations.Instance.ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } public class ToXyzw_Rgba32 : ToXyzw diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 5ef8f0111f..5d163917cd 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -2,7 +2,7 @@ net462;net471;netcoreapp2.1 True - 7.3 + latest full portable True @@ -11,15 +11,15 @@ AnyCPU;x64;x86 - true + false - true + false - true + false diff --git a/tests/ImageSharp.Tests/Issues/Issue594.cs b/tests/ImageSharp.Tests/Issues/Issue594.cs index 81fd59885a..4a0683fba7 100644 --- a/tests/ImageSharp.Tests/Issues/Issue594.cs +++ b/tests/ImageSharp.Tests/Issues/Issue594.cs @@ -48,46 +48,46 @@ namespace SixLabors.ImageSharp.Tests.Issues Assert.Equal((uint)958796544, new NormalizedByte4(0.0008f, 0.15f, 0.30f, 0.45f).PackedValue); - var rgb = default(Rgb24); - var rgba = default(Rgba32); - var bgr = default(Bgr24); - var bgra = default(Bgra32); - var argb = default(Argb32); + //var rgb = default(Rgb24); + //var rgba = default(Rgba32); + //var bgr = default(Bgr24); + //var bgra = default(Bgra32); + //var argb = default(Argb32); - new NormalizedByte4(x, y, z, w).ToRgb24(ref rgb); - Assert.Equal(rgb, new Rgb24(141, 90, 192)); + //new NormalizedByte4(x, y, z, w).ToRgb24(ref rgb); + //Assert.Equal(rgb, new Rgb24(141, 90, 192)); - new NormalizedByte4(x, y, z, w).ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(141, 90, 192, 39)); + //new NormalizedByte4(x, y, z, w).ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(141, 90, 192, 39)); - new NormalizedByte4(x, y, z, w).ToBgr24(ref bgr); - Assert.Equal(bgr, new Bgr24(141, 90, 192)); + //new NormalizedByte4(x, y, z, w).ToBgr24(ref bgr); + //Assert.Equal(bgr, new Bgr24(141, 90, 192)); - new NormalizedByte4(x, y, z, w).ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(141, 90, 192, 39)); // this assert fails in Release build on linux (#594) + //new NormalizedByte4(x, y, z, w).ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(141, 90, 192, 39)); // this assert fails in Release build on linux (#594) - new NormalizedByte4(x, y, z, w).ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(141, 90, 192, 39)); + //new NormalizedByte4(x, y, z, w).ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(141, 90, 192, 39)); // http://community.monogame.net/t/normalizedbyte4-texture2d-gives-different-results-from-xna/8012/8 - var r = default(NormalizedByte4); - r.PackFromRgba32(new Rgba32(9, 115, 202, 127)); - r.ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); - - r.PackedValue = 0xff4af389; - r.ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); - - r = default(NormalizedByte4); - r.PackFromArgb32(new Argb32(9, 115, 202, 127)); - r.ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(9, 115, 202, 127)); - - r = default(NormalizedByte4); - r.PackFromBgra32(new Bgra32(9, 115, 202, 127)); - r.ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); + //var r = default(NormalizedByte4); + //r.PackFromRgba32(new Rgba32(9, 115, 202, 127)); + //r.ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); + + //r.PackedValue = 0xff4af389; + //r.ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); + + //r = default(NormalizedByte4); + //r.PackFromArgb32(new Argb32(9, 115, 202, 127)); + //r.ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(9, 115, 202, 127)); + + //r = default(NormalizedByte4); + //r.PackFromBgra32(new Bgra32(9, 115, 202, 127)); + //r.ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); } // This test fails for unknown reason in Release mode on linux and is meant to help reproducing the issue @@ -127,41 +127,41 @@ namespace SixLabors.ImageSharp.Tests.Issues Assert.Equal(0xa6674000d99a0ccd, new NormalizedShort4(x, y, z, w).PackedValue); Assert.Equal((ulong)4150390751449251866, new NormalizedShort4(0.0008f, 0.15f, 0.30f, 0.45f).PackedValue); - var rgb = default(Rgb24); - var rgba = default(Rgba32); - var bgr = default(Bgr24); - var bgra = default(Bgra32); - var argb = default(Argb32); + //var rgb = default(Rgb24); + //var rgba = default(Rgba32); + //var bgr = default(Bgr24); + //var bgra = default(Bgra32); + //var argb = default(Argb32); - new NormalizedShort4(x, y, z, w).ToRgb24(ref rgb); - Assert.Equal(rgb, new Rgb24(141, 90, 192)); + //new NormalizedShort4(x, y, z, w).ToRgb24(ref rgb); + //Assert.Equal(rgb, new Rgb24(141, 90, 192)); - new NormalizedShort4(x, y, z, w).ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(141, 90, 192, 39)); // this assert fails in Release build on linux (#594) + //new NormalizedShort4(x, y, z, w).ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(141, 90, 192, 39)); // this assert fails in Release build on linux (#594) - new NormalizedShort4(x, y, z, w).ToBgr24(ref bgr); - Assert.Equal(bgr, new Bgr24(141, 90, 192)); + //new NormalizedShort4(x, y, z, w).ToBgr24(ref bgr); + //Assert.Equal(bgr, new Bgr24(141, 90, 192)); - new NormalizedShort4(x, y, z, w).ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(141, 90, 192, 39)); + //new NormalizedShort4(x, y, z, w).ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(141, 90, 192, 39)); - new NormalizedShort4(x, y, z, w).ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(141, 90, 192, 39)); + //new NormalizedShort4(x, y, z, w).ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(141, 90, 192, 39)); - var r = default(NormalizedShort4); - r.PackFromRgba32(new Rgba32(9, 115, 202, 127)); - r.ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); + //var r = default(NormalizedShort4); + //r.PackFromRgba32(new Rgba32(9, 115, 202, 127)); + //r.ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); - r = default(NormalizedShort4); - r.PackFromBgra32(new Bgra32(9, 115, 202, 127)); - r.ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); + //r = default(NormalizedShort4); + //r.PackFromBgra32(new Bgra32(9, 115, 202, 127)); + //r.ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); - r = default(NormalizedShort4); - r.PackFromArgb32(new Argb32(9, 115, 202, 127)); - r.ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(9, 115, 202, 127)); + //r = default(NormalizedShort4); + //r.PackFromArgb32(new Argb32(9, 115, 202, 127)); + //r.ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(9, 115, 202, 127)); } // This test fails for unknown reason in Release mode on linux and is meant to help reproducing the issue @@ -212,41 +212,41 @@ namespace SixLabors.ImageSharp.Tests.Issues w = 193; Assert.Equal((ulong)0x00c173b7316d2d1b, new Short4(x, y, z, w).PackedValue); - var rgb = default(Rgb24); - var rgba = default(Rgba32); - var bgr = default(Bgr24); - var bgra = default(Bgra32); - var argb = default(Argb32); + //var rgb = default(Rgb24); + //var rgba = default(Rgba32); + //var bgr = default(Bgr24); + //var bgra = default(Bgra32); + //var argb = default(Argb32); - new Short4(x, y, z, w).ToRgb24(ref rgb); - Assert.Equal(rgb, new Rgb24(172, 177, 243)); // this assert fails in Release build on linux (#594) + //new Short4(x, y, z, w).ToRgb24(ref rgb); + //Assert.Equal(rgb, new Rgb24(172, 177, 243)); // this assert fails in Release build on linux (#594) - new Short4(x, y, z, w).ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(172, 177, 243, 128)); + //new Short4(x, y, z, w).ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(172, 177, 243, 128)); - new Short4(x, y, z, w).ToBgr24(ref bgr); - Assert.Equal(bgr, new Bgr24(172, 177, 243)); + //new Short4(x, y, z, w).ToBgr24(ref bgr); + //Assert.Equal(bgr, new Bgr24(172, 177, 243)); - new Short4(x, y, z, w).ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(172, 177, 243, 128)); + //new Short4(x, y, z, w).ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(172, 177, 243, 128)); - new Short4(x, y, z, w).ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(172, 177, 243, 128)); + //new Short4(x, y, z, w).ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(172, 177, 243, 128)); - var r = default(Short4); - r.PackFromRgba32(new Rgba32(20, 38, 0, 255)); - r.ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(20, 38, 0, 255)); + //var r = default(Short4); + //r.PackFromRgba32(new Rgba32(20, 38, 0, 255)); + //r.ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(20, 38, 0, 255)); - r = default(Short4); - r.PackFromBgra32(new Bgra32(20, 38, 0, 255)); - r.ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(20, 38, 0, 255)); + //r = default(Short4); + //r.PackFromBgra32(new Bgra32(20, 38, 0, 255)); + //r.ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(20, 38, 0, 255)); - r = default(Short4); - r.PackFromArgb32(new Argb32(20, 38, 0, 255)); - r.ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(20, 38, 0, 255)); + //r = default(Short4); + //r.PackFromArgb32(new Argb32(20, 38, 0, 255)); + //r.ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(20, 38, 0, 255)); } // Comparison helpers with small tolerance to allow for floating point rounding during computations. diff --git a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs index 9a29236dba..d5b7d9b2b2 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs @@ -73,138 +73,138 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } - [Fact] - public void Alpha8_PackFromScaledVector4_ToRgb24() - { - // arrange - Rgb24 actual = default; - Alpha8 alpha = default; - var expected = new Rgb24(0, 0, 0); - Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); - - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromScaledVector4_ToRgba32() - { - // arrange - Rgba32 actual = default; - Alpha8 alpha = default; - var expected = new Rgba32(0, 0, 0, 128); - Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); - - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromScaledVector4_ToBgr24() - { - // arrange - Bgr24 actual = default; - Alpha8 alpha = default; - var expected = new Bgr24(0, 0, 0); - Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); - - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromScaledVector4_ToBgra32() - { - // arrange - Bgra32 actual = default; - Alpha8 alpha = default; - var expected = new Bgra32(0, 0, 0, 128); - Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); - - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromScaledVector4_ToArgb32() - { - // arrange - Alpha8 alpha = default; - Argb32 actual = default; - var expected = new Argb32(0, 0, 0, 128); - Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); - - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromScaledVector4_ToRgba64() - { - // arrange - Alpha8 alpha = default; - Rgba64 actual = default; - var expected = new Rgba64(0, 0, 0, 65535); - Vector4 scaled = new Alpha8(1F).ToScaledVector4(); - - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromRgb48_ToRgb48() - { - // arrange - var alpha = default(Alpha8); - var actual = default(Rgb48); - var expected = new Rgb48(0, 0, 0); - - // act - alpha.PackFromRgb48(expected); - alpha.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromRgba64_ToRgba64() - { - // arrange - var alpha = default(Alpha8); - var actual = default(Rgba64); - var expected = new Rgba64(0, 0, 0, 65535); - - // act - alpha.PackFromRgba64(expected); - alpha.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void Alpha8_PackFromScaledVector4_ToRgb24() + //{ + // // arrange + // Rgb24 actual = default; + // Alpha8 alpha = default; + // var expected = new Rgb24(0, 0, 0); + // Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); + + // // act + // alpha.PackFromScaledVector4(scaled); + // alpha.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Alpha8_PackFromScaledVector4_ToRgba32() + //{ + // // arrange + // Rgba32 actual = default; + // Alpha8 alpha = default; + // var expected = new Rgba32(0, 0, 0, 128); + // Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); + + // // act + // alpha.PackFromScaledVector4(scaled); + // alpha.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Alpha8_PackFromScaledVector4_ToBgr24() + //{ + // // arrange + // Bgr24 actual = default; + // Alpha8 alpha = default; + // var expected = new Bgr24(0, 0, 0); + // Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); + + // // act + // alpha.PackFromScaledVector4(scaled); + // alpha.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Alpha8_PackFromScaledVector4_ToBgra32() + //{ + // // arrange + // Bgra32 actual = default; + // Alpha8 alpha = default; + // var expected = new Bgra32(0, 0, 0, 128); + // Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); + + // // act + // alpha.PackFromScaledVector4(scaled); + // alpha.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Alpha8_PackFromScaledVector4_ToArgb32() + //{ + // // arrange + // Alpha8 alpha = default; + // Argb32 actual = default; + // var expected = new Argb32(0, 0, 0, 128); + // Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); + + // // act + // alpha.PackFromScaledVector4(scaled); + // alpha.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Alpha8_PackFromScaledVector4_ToRgba64() + //{ + // // arrange + // Alpha8 alpha = default; + // Rgba64 actual = default; + // var expected = new Rgba64(0, 0, 0, 65535); + // Vector4 scaled = new Alpha8(1F).ToScaledVector4(); + + // // act + // alpha.PackFromScaledVector4(scaled); + // alpha.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Alpha8_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var alpha = default(Alpha8); + // var actual = default(Rgb48); + // var expected = new Rgb48(0, 0, 0); + + // // act + // alpha.PackFromRgb48(expected); + // alpha.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Alpha8_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var alpha = default(Alpha8); + // var actual = default(Rgba64); + // var expected = new Rgba64(0, 0, 0, 65535); + + // // act + // alpha.PackFromRgba64(expected); + // alpha.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs index 5817b5c329..53545f517a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs @@ -67,159 +67,159 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One, new Argb32(Vector4.One * +1234.0f).ToVector4()); } - [Fact] - public void Argb32_ToRgb24() - { - // arrange - var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(0x1a, 0, 0x80); - - // act - argb.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_ToRgba32() - { - // arrange - var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(0x1a, 0, 0x80, 0); - - // act - argb.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_ToBgr24() - { - // arrange - var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(0x1a, 0, 0x80); - - // act - argb.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_ToBgra32() - { - // arrange - var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(0x1a, 0, 0x80, 0); - - // act - argb.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_ToArgb32() - { - // arrange - var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(0x1a, 0, 0x80, 0); - - // act - argb.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_PackFromRgba32_ToRgba32() - { - // arrange - var argb = default(Argb32); - var actual = default(Rgba32); - var expected = new Rgba32(0x1a, 0, 0x80, 0); - - // act - argb.PackFromRgba32(expected); - argb.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_PackFromBgra32_ToBgra32() - { - // arrange - var argb = default(Argb32); - var actual = default(Bgra32); - var expected = new Bgra32(0x1a, 0, 0x80, 0); - - // act - argb.PackFromBgra32(expected); - argb.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_PackFromArgb32_ToArgb32() - { - // arrange - var argb = default(Argb32); - var actual = default(Argb32); - var expected = new Argb32(0x1a, 0, 0x80, 0); - - // act - argb.PackFromArgb32(expected); - argb.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_PackFromRgb48_ToRgb48() - { - // arrange - var argb = default(Argb32); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - argb.PackFromRgb48(expected); - argb.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_PackFromRgba64_ToRgba64() - { - // arrange - var argb = default(Argb32); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - argb.PackFromRgba64(expected); - argb.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void Argb32_ToRgb24() + //{ + // // arrange + // var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); + // var actual = default(Rgb24); + // var expected = new Rgb24(0x1a, 0, 0x80); + + // // act + // argb.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Argb32_ToRgba32() + //{ + // // arrange + // var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); + // var actual = default(Rgba32); + // var expected = new Rgba32(0x1a, 0, 0x80, 0); + + // // act + // argb.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Argb32_ToBgr24() + //{ + // // arrange + // var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); + // var actual = default(Bgr24); + // var expected = new Bgr24(0x1a, 0, 0x80); + + // // act + // argb.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Argb32_ToBgra32() + //{ + // // arrange + // var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); + // var actual = default(Bgra32); + // var expected = new Bgra32(0x1a, 0, 0x80, 0); + + // // act + // argb.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Argb32_ToArgb32() + //{ + // // arrange + // var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); + // var actual = default(Argb32); + // var expected = new Argb32(0x1a, 0, 0x80, 0); + + // // act + // argb.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Argb32_PackFromRgba32_ToRgba32() + //{ + // // arrange + // var argb = default(Argb32); + // var actual = default(Rgba32); + // var expected = new Rgba32(0x1a, 0, 0x80, 0); + + // // act + // argb.PackFromRgba32(expected); + // argb.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Argb32_PackFromBgra32_ToBgra32() + //{ + // // arrange + // var argb = default(Argb32); + // var actual = default(Bgra32); + // var expected = new Bgra32(0x1a, 0, 0x80, 0); + + // // act + // argb.PackFromBgra32(expected); + // argb.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Argb32_PackFromArgb32_ToArgb32() + //{ + // // arrange + // var argb = default(Argb32); + // var actual = default(Argb32); + // var expected = new Argb32(0x1a, 0, 0x80, 0); + + // // act + // argb.PackFromArgb32(expected); + // argb.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Argb32_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var argb = default(Argb32); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 0, 65535); + + // // act + // argb.PackFromRgb48(expected); + // argb.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Argb32_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var argb = default(Argb32); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 0, 65535, 0); + + // // act + // argb.PackFromRgba64(expected); + // argb.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs index 048a38380e..e742789e4d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs @@ -96,80 +96,80 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); } - [Fact] - public void ToRgb24() - { - var rgb = new Bgr24(1, 2, 3); - var dest = default(Rgb24); - - rgb.ToRgb24(ref dest); - - Assert.Equal(new Rgb24(1, 2, 3), dest); - } - - [Fact] - public void ToRgba32() - { - var rgb = new Bgr24(1, 2, 3); - var rgba = default(Rgba32); - - rgb.ToRgba32(ref rgba); - - Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); - } - - [Fact] - public void ToBgr24() - { - var rgb = new Bgr24(1, 2, 3); - var bgr = default(Bgr24); - - rgb.ToBgr24(ref bgr); - - Assert.Equal(new Bgr24(1, 2, 3), bgr); - } - - [Fact] - public void ToBgra32() - { - var rgb = new Bgr24(1, 2, 3); - var bgra = default(Bgra32); - - rgb.ToBgra32(ref bgra); - - Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); - } - - [Fact] - public void Bgr24_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Bgr24); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr24_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Bgr24); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void ToRgb24() + //{ + // var rgb = new Bgr24(1, 2, 3); + // var dest = default(Rgb24); + + // rgb.ToRgb24(ref dest); + + // Assert.Equal(new Rgb24(1, 2, 3), dest); + //} + + //[Fact] + //public void ToRgba32() + //{ + // var rgb = new Bgr24(1, 2, 3); + // var rgba = default(Rgba32); + + // rgb.ToRgba32(ref rgba); + + // Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); + //} + + //[Fact] + //public void ToBgr24() + //{ + // var rgb = new Bgr24(1, 2, 3); + // var bgr = default(Bgr24); + + // rgb.ToBgr24(ref bgr); + + // Assert.Equal(new Bgr24(1, 2, 3), bgr); + //} + + //[Fact] + //public void ToBgra32() + //{ + // var rgb = new Bgr24(1, 2, 3); + // var bgra = default(Bgra32); + + // rgb.ToBgra32(ref bgra); + + // Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); + //} + + //[Fact] + //public void Bgr24_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(Bgr24); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 0, 65535); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgr24_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(Bgr24); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 0, 65535, 65535); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs index b66cac9ca3..6954067a34 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs @@ -70,111 +70,111 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector3.One, new Bgr565(Vector3.One * 1234F).ToVector3()); } - [Fact] - public void Bgr565_ToRgb24() - { - // arrange - var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - var actual = default(Rgb24); - var expected = new Rgb24(25, 0, 132); - - // act - bgra.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_ToRgba32() - { - // arrange - var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - var actual = default(Rgba32); - var expected = new Rgba32(25, 0, 132, 255); - - // act - bgra.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_ToBgr24() - { - // arrange - var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - var actual = default(Bgr24); - var expected = new Bgr24(25, 0, 132); - - // act - bgra.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_ToBgra32() - { - // arrange - var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - var actual = default(Bgra32); - var expected = new Bgra32(25, 0, 132, 255); - - // act - bgra.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_ToArgb32() - { - // arrange - var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - var actual = default(Argb32); - var expected = new Argb32(25, 0, 132, 255); - - // act - bgra.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Bgr565); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Bgr565); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void Bgr565_ToRgb24() + //{ + // // arrange + // var bgra = new Bgr565(0.1F, -0.3F, 0.5F); + // var actual = default(Rgb24); + // var expected = new Rgb24(25, 0, 132); + + // // act + // bgra.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgr565_ToRgba32() + //{ + // // arrange + // var bgra = new Bgr565(0.1F, -0.3F, 0.5F); + // var actual = default(Rgba32); + // var expected = new Rgba32(25, 0, 132, 255); + + // // act + // bgra.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgr565_ToBgr24() + //{ + // // arrange + // var bgra = new Bgr565(0.1F, -0.3F, 0.5F); + // var actual = default(Bgr24); + // var expected = new Bgr24(25, 0, 132); + + // // act + // bgra.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgr565_ToBgra32() + //{ + // // arrange + // var bgra = new Bgr565(0.1F, -0.3F, 0.5F); + // var actual = default(Bgra32); + // var expected = new Bgra32(25, 0, 132, 255); + + // // act + // bgra.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgr565_ToArgb32() + //{ + // // arrange + // var bgra = new Bgr565(0.1F, -0.3F, 0.5F); + // var actual = default(Argb32); + // var expected = new Argb32(25, 0, 132, 255); + + // // act + // bgra.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgr565_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(Bgr565); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 0, 65535); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgr565_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(Bgr565); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 0, 65535, 65535); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs index 70f8c35dfc..9ff84a88c1 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs @@ -103,80 +103,80 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vec(1, 2, 3, 4), rgb.ToVector4()); } - [Fact] - public void ToRgb24() - { - var c = new Bgra32(1, 2, 3, 4); - var dest = default(Rgb24); - - c.ToRgb24(ref dest); - - Assert.Equal(new Rgb24(1, 2, 3), dest); - } - - [Fact] - public void ToRgba32() - { - var c = new Bgra32(1, 2, 3, 4); - var rgba = default(Rgba32); - - c.ToRgba32(ref rgba); - - Assert.Equal(new Rgba32(1, 2, 3, 4), rgba); - } - - [Fact] - public void ToBgr24() - { - var rgb = new Bgra32(1, 2, 3, 4); - var bgr = default(Bgr24); - - rgb.ToBgr24(ref bgr); - - Assert.Equal(new Bgr24(1, 2, 3), bgr); - } - - [Fact] - public void ToBgra32() - { - var rgb = new Bgra32(1, 2, 3, 4); - var bgra = default(Bgra32); - - rgb.ToBgra32(ref bgra); - - Assert.Equal(new Bgra32(1, 2, 3, 4), bgra); - } - - [Fact] - public void Bgra32_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Bgra32); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra32_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Bgra32); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void ToRgb24() + //{ + // var c = new Bgra32(1, 2, 3, 4); + // var dest = default(Rgb24); + + // c.ToRgb24(ref dest); + + // Assert.Equal(new Rgb24(1, 2, 3), dest); + //} + + //[Fact] + //public void ToRgba32() + //{ + // var c = new Bgra32(1, 2, 3, 4); + // var rgba = default(Rgba32); + + // c.ToRgba32(ref rgba); + + // Assert.Equal(new Rgba32(1, 2, 3, 4), rgba); + //} + + //[Fact] + //public void ToBgr24() + //{ + // var rgb = new Bgra32(1, 2, 3, 4); + // var bgr = default(Bgr24); + + // rgb.ToBgr24(ref bgr); + + // Assert.Equal(new Bgr24(1, 2, 3), bgr); + //} + + //[Fact] + //public void ToBgra32() + //{ + // var rgb = new Bgra32(1, 2, 3, 4); + // var bgra = default(Bgra32); + + // rgb.ToBgra32(ref bgra); + + // Assert.Equal(new Bgra32(1, 2, 3, 4), bgra); + //} + + //[Fact] + //public void Bgra32_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(Bgra32); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 0, 65535); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra32_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(Bgra32); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 0, 65535, 0); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs index f643d152ef..2e6e339b6a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs @@ -71,159 +71,159 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One, new Bgra4444(Vector4.One * 1234.0f).ToVector4()); } - [Fact] - public void Bgra4444_ToRgb24() - { - // arrange - var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(34, 0, 136); - - // act - bgra.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_ToRgba32() - { - // arrange - var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(34, 0, 136, 0); - - // act - bgra.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_ToBgr24() - { - // arrange - var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(34, 0, 136); - - // act - bgra.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_ToBgra32() - { - // arrange - var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(34, 0, 136, 0); - - // act - bgra.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_ToArgb32() - { - // arrange - var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(34, 0, 136, 0); - - // act - bgra.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_PackFromRgba32_ToRgba32() - { - // arrange - var bgra = default(Bgra4444); - var actual = default(Rgba32); - var expected = new Rgba32(34, 0, 136, 0); - - // act - bgra.PackFromRgba32(expected); - bgra.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_PackFromBgra32_ToBgra32() - { - // arrange - var bgra = default(Bgra4444); - var actual = default(Bgra32); - var expected = new Bgra32(34, 0, 136, 0); - - // act - bgra.PackFromBgra32(expected); - bgra.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_PackFromArgb32_ToArgb32() - { - // arrange - var bgra = default(Bgra4444); - var actual = default(Argb32); - var expected = new Argb32(34, 0, 136, 0); - - // act - bgra.PackFromArgb32(expected); - bgra.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Bgra4444); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Bgra4444); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void Bgra4444_ToRgb24() + //{ + // // arrange + // var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Rgb24); + // var expected = new Rgb24(34, 0, 136); + + // // act + // bgra.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra4444_ToRgba32() + //{ + // // arrange + // var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Rgba32); + // var expected = new Rgba32(34, 0, 136, 0); + + // // act + // bgra.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra4444_ToBgr24() + //{ + // // arrange + // var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Bgr24); + // var expected = new Bgr24(34, 0, 136); + + // // act + // bgra.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra4444_ToBgra32() + //{ + // // arrange + // var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Bgra32); + // var expected = new Bgra32(34, 0, 136, 0); + + // // act + // bgra.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra4444_ToArgb32() + //{ + // // arrange + // var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Argb32); + // var expected = new Argb32(34, 0, 136, 0); + + // // act + // bgra.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra4444_PackFromRgba32_ToRgba32() + //{ + // // arrange + // var bgra = default(Bgra4444); + // var actual = default(Rgba32); + // var expected = new Rgba32(34, 0, 136, 0); + + // // act + // bgra.PackFromRgba32(expected); + // bgra.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra4444_PackFromBgra32_ToBgra32() + //{ + // // arrange + // var bgra = default(Bgra4444); + // var actual = default(Bgra32); + // var expected = new Bgra32(34, 0, 136, 0); + + // // act + // bgra.PackFromBgra32(expected); + // bgra.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra4444_PackFromArgb32_ToArgb32() + //{ + // // arrange + // var bgra = default(Bgra4444); + // var actual = default(Argb32); + // var expected = new Argb32(34, 0, 136, 0); + + // // act + // bgra.PackFromArgb32(expected); + // bgra.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra4444_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(Bgra4444); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 0, 65535); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra4444_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(Bgra4444); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 0, 65535, 0); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs index b6a0780312..3a0aec3209 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs @@ -70,159 +70,159 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One, new Bgra5551(Vector4.One * 1234.0f).ToVector4()); } - [Fact] - public void Bgra5551_ToRgb24() - { - // arrange - var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(24, 0, 131); - - // act - bgra.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_Rgba32() - { - // arrange - var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(24, 0, 131, 0); - - // act - bgra.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_ToBgr24() - { - // arrange - var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(24, 0, 131); - - // act - bgra.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_Bgra32() - { - // arrange - var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(24, 0, 131, 0); - - // act - bgra.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_ToArgb32() - { - // arrange - var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(24, 0, 131, 0); - - // act - bgra.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_PackFromRgba32_ToRgba32() - { - // arrange - var bgra = default(Bgra5551); - var expected = new Rgba32(24, 0, 131, 0); - var actual = default(Rgba32); - - // act - bgra.PackFromRgba32(expected); - bgra.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_PackFromBgra32_ToBgra32() - { - // arrange - var bgra = default(Bgra5551); - var expected = new Bgra32(24, 0, 131, 0); - var actual = default(Bgra32); - - // act - bgra.PackFromBgra32(expected); - bgra.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_PackFromArgb32_ToArgb32() - { - // arrange - var bgra = default(Bgra5551); - var expected = new Argb32(24, 0, 131, 0); - var actual = default(Argb32); - - // act - bgra.PackFromArgb32(expected); - bgra.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Bgra5551); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Bgra5551); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void Bgra5551_ToRgb24() + //{ + // // arrange + // var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Rgb24); + // var expected = new Rgb24(24, 0, 131); + + // // act + // bgra.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra5551_Rgba32() + //{ + // // arrange + // var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Rgba32); + // var expected = new Rgba32(24, 0, 131, 0); + + // // act + // bgra.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra5551_ToBgr24() + //{ + // // arrange + // var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Bgr24); + // var expected = new Bgr24(24, 0, 131); + + // // act + // bgra.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra5551_Bgra32() + //{ + // // arrange + // var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Bgra32); + // var expected = new Bgra32(24, 0, 131, 0); + + // // act + // bgra.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra5551_ToArgb32() + //{ + // // arrange + // var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Argb32); + // var expected = new Argb32(24, 0, 131, 0); + + // // act + // bgra.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra5551_PackFromRgba32_ToRgba32() + //{ + // // arrange + // var bgra = default(Bgra5551); + // var expected = new Rgba32(24, 0, 131, 0); + // var actual = default(Rgba32); + + // // act + // bgra.PackFromRgba32(expected); + // bgra.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra5551_PackFromBgra32_ToBgra32() + //{ + // // arrange + // var bgra = default(Bgra5551); + // var expected = new Bgra32(24, 0, 131, 0); + // var actual = default(Bgra32); + + // // act + // bgra.PackFromBgra32(expected); + // bgra.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra5551_PackFromArgb32_ToArgb32() + //{ + // // arrange + // var bgra = default(Bgra5551); + // var expected = new Argb32(24, 0, 131, 0); + // var actual = default(Argb32); + + // // act + // bgra.PackFromArgb32(expected); + // bgra.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra5551_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(Bgra5551); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 0, 65535); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra5551_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(Bgra5551); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 0, 65535, 0); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs index 28555a7dff..d1e8cceaa4 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs @@ -68,159 +68,159 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One * 255, new Byte4(Vector4.One * 1234.0f).ToVector4()); } - [Fact] - public void Byte4_ToRgb24() - { - // arrange - var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(128, 0, 0); - - // act - byte4.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_Rgba32() - { - // arrange - var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(128, 0, 0, 0); - - // act - byte4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_ToBgr24() - { - // arrange - var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(128, 0, 0); - - // act - byte4.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_Bgra32() - { - // arrange - var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(128, 0, 0, 0); - - // act - byte4.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_Argb32() - { - // arrange - var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(128, 0, 0, 0); - - // act - byte4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_PackFromRgba32_ToRgba32() - { - // arrange - var byte4 = default(Byte4); - var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 0, 255); - - // act - byte4.PackFromRgba32(expected); - byte4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_PackFromBgra32_ToBgra32() - { - // arrange - var byte4 = default(Byte4); - var actual = default(Bgra32); - var expected = new Bgra32(20, 38, 0, 255); - - // act - byte4.PackFromBgra32(expected); - byte4.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_PackFromArgb32_ToArgb32() - { - // arrange - var byte4 = default(Byte4); - var actual = default(Argb32); - var expected = new Argb32(20, 38, 0, 255); - - // act - byte4.PackFromArgb32(expected); - byte4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Byte4); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Byte4); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void Byte4_ToRgb24() + //{ + // // arrange + // var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); + // var actual = default(Rgb24); + // var expected = new Rgb24(128, 0, 0); + + // // act + // byte4.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Byte4_Rgba32() + //{ + // // arrange + // var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); + // var actual = default(Rgba32); + // var expected = new Rgba32(128, 0, 0, 0); + + // // act + // byte4.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Byte4_ToBgr24() + //{ + // // arrange + // var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); + // var actual = default(Bgr24); + // var expected = new Bgr24(128, 0, 0); + + // // act + // byte4.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Byte4_Bgra32() + //{ + // // arrange + // var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); + // var actual = default(Bgra32); + // var expected = new Bgra32(128, 0, 0, 0); + + // // act + // byte4.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Byte4_Argb32() + //{ + // // arrange + // var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); + // var actual = default(Argb32); + // var expected = new Argb32(128, 0, 0, 0); + + // // act + // byte4.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Byte4_PackFromRgba32_ToRgba32() + //{ + // // arrange + // var byte4 = default(Byte4); + // var actual = default(Rgba32); + // var expected = new Rgba32(20, 38, 0, 255); + + // // act + // byte4.PackFromRgba32(expected); + // byte4.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Byte4_PackFromBgra32_ToBgra32() + //{ + // // arrange + // var byte4 = default(Byte4); + // var actual = default(Bgra32); + // var expected = new Bgra32(20, 38, 0, 255); + + // // act + // byte4.PackFromBgra32(expected); + // byte4.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Byte4_PackFromArgb32_ToArgb32() + //{ + // // arrange + // var byte4 = default(Byte4); + // var actual = default(Argb32); + // var expected = new Argb32(20, 38, 0, 255); + + // // act + // byte4.PackFromArgb32(expected); + // byte4.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Byte4_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(Byte4); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 0, 65535); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Byte4_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(Byte4); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 0, 65535, 0); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/ColorConstructorTests.cs b/tests/ImageSharp.Tests/PixelFormats/ColorConstructorTests.cs deleted file mode 100644 index b0d5929f49..0000000000 --- a/tests/ImageSharp.Tests/PixelFormats/ColorConstructorTests.cs +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Collections.Generic; -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.Colors -{ - public class ColorConstructorTests - { - public static IEnumerable Vector4Data - { - get - { - Vector4[] vector4Values = new Vector4[] - { - Vector4.Zero, - Vector4.One, - Vector4.UnitX, - Vector4.UnitY, - Vector4.UnitZ, - Vector4.UnitW, - }; - - foreach (Vector4 vector4 in vector4Values) - { - // using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { new Argb32(vector4), vector4Components }; - yield return new object[] { new Bgra4444(vector4), vector4Components }; - yield return new object[] { new Bgra5551(vector4), vector4Components }; - yield return new object[] { new Byte4(vector4), vector4Components }; - yield return new object[] { new HalfVector4(vector4), vector4Components }; - yield return new object[] { new NormalizedByte4(vector4), vector4Components }; - yield return new object[] { new NormalizedShort4(vector4), vector4Components }; - yield return new object[] { new Rgba1010102(vector4), vector4Components }; - yield return new object[] { new Rgba64(vector4), vector4Components }; - yield return new object[] { new Short4(vector4), vector4Components }; - } - } - } - - public static IEnumerable Vector3Data - { - get - { - Dictionary vector3Values = new Dictionary() - { - { Vector3.One, Vector4.One }, - { Vector3.Zero, new Vector4(0, 0, 0, 1) }, - { Vector3.UnitX, new Vector4(1, 0, 0, 1) }, - { Vector3.UnitY, new Vector4(0, 1, 0, 1) }, - { Vector3.UnitZ, new Vector4(0, 0, 1, 1) }, - }; - - foreach (Vector3 vector3 in vector3Values.Keys) - { - Vector4 vector4 = vector3Values[vector3]; - // using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { new Argb32(vector3), vector4Components }; - yield return new object[] { new Bgr565(vector3), vector4Components }; - } - } - } - - public static IEnumerable Float4Data - { - get - { - Vector4[] vector4Values = new Vector4[] - { - Vector4.Zero, - Vector4.One, - Vector4.UnitX, - Vector4.UnitY, - Vector4.UnitZ, - Vector4.UnitW, - }; - - foreach (Vector4 vector4 in vector4Values) - { - // using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { new Argb32(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Bgra4444(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Bgra5551(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Byte4(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new HalfVector4(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new NormalizedByte4(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new NormalizedShort4(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Rgba1010102(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Rgba64(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Short4(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - } - } - } - - public static IEnumerable Float3Data - { - get - { - Dictionary vector3Values = new Dictionary() - { - { Vector3.One, Vector4.One }, - { Vector3.Zero, new Vector4(0, 0, 0, 1) }, - { Vector3.UnitX, new Vector4(1, 0, 0, 1) }, - { Vector3.UnitY, new Vector4(0, 1, 0, 1) }, - { Vector3.UnitZ, new Vector4(0, 0, 1, 1) }, - }; - - foreach (Vector3 vector3 in vector3Values.Keys) - { - Vector4 vector4 = vector3Values[vector3]; - // using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { new Argb32(vector3.X, vector3.Y, vector3.Z), vector4Components }; - yield return new object[] { new Bgr565(vector3.X, vector3.Y, vector3.Z), vector4Components }; - } - } - } - - [Theory] - [MemberData(nameof(Vector4Data))] - [MemberData(nameof(Vector3Data))] - [MemberData(nameof(Float4Data))] - [MemberData(nameof(Float3Data))] - public void ConstructorToVector4(IPixel packedVector, float[] expectedVector4Components) - { - // Arrange - int precision = 2; - // using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData - Vector4 expectedVector4 = new Vector4(expectedVector4Components[0], expectedVector4Components[1], expectedVector4Components[2], expectedVector4Components[3]); - - // Act - Vector4 vector4 = packedVector.ToVector4(); - - // Assert - Assert.Equal(expectedVector4.X, vector4.X, precision); - Assert.Equal(expectedVector4.Y, vector4.Y, precision); - Assert.Equal(expectedVector4.Z, vector4.Z, precision); - Assert.Equal(expectedVector4.W, vector4.W, precision); - } - } -} diff --git a/tests/ImageSharp.Tests/PixelFormats/ColorEqualityTests.cs b/tests/ImageSharp.Tests/PixelFormats/ColorEqualityTests.cs deleted file mode 100644 index d3815f2eb6..0000000000 --- a/tests/ImageSharp.Tests/PixelFormats/ColorEqualityTests.cs +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.Colors -{ - /// - /// Test implementations of IEquatable - /// - public class ColorEqualityTests - { - public static readonly TheoryData EqualityData = - new TheoryData() - { - { new Alpha8(.5F), new Alpha8(.5F), typeof(Alpha8) }, - { new Argb32(Vector4.One), new Argb32(Vector4.One), typeof(Argb32) }, - { new Bgr565(Vector3.One), new Bgr565(Vector3.One), typeof(Bgr565) }, - { new Bgra4444(Vector4.One), new Bgra4444(Vector4.One), typeof(Bgra4444) }, - { new Bgra5551(Vector4.One), new Bgra5551(Vector4.One), typeof(Bgra5551) }, - { new Byte4(Vector4.One * 255), new Byte4(Vector4.One * 255), typeof(Byte4) }, - { new HalfSingle(-1F), new HalfSingle(-1F), typeof(HalfSingle) }, - { new HalfVector2(0.1f, -0.3f), new HalfVector2(0.1f, -0.3f), typeof(HalfVector2) }, - { new HalfVector4(Vector4.One), new HalfVector4(Vector4.One), typeof(HalfVector4) }, - { new NormalizedByte2(-Vector2.One), new NormalizedByte2(-Vector2.One), typeof(NormalizedByte2) }, - { new NormalizedByte4(Vector4.One), new NormalizedByte4(Vector4.One), typeof(NormalizedByte4) }, - { new NormalizedShort2(Vector2.One), new NormalizedShort2(Vector2.One), typeof(NormalizedShort2) }, - { new NormalizedShort4(Vector4.One), new NormalizedShort4(Vector4.One), typeof(NormalizedShort4) }, - { new Rg32(Vector2.One), new Rg32(Vector2.One), typeof(Rg32) }, - { new Rgba1010102(Vector4.One), new Rgba1010102(Vector4.One), typeof(Rgba1010102) }, - { new Rgba32(Vector4.One), new Rgba32(Vector4.One), typeof(Rgba32) }, - { new Rgba64(Vector4.One), new Rgba64(Vector4.One), typeof(Rgba64) }, - { new Short2(Vector2.One * 0x7FFF), new Short2(Vector2.One * 0x7FFF), typeof(Short2) }, - { new Short4(Vector4.One * 0x7FFF), new Short4(Vector4.One * 0x7FFF), typeof(Short4) }, - }; - - public static readonly TheoryData NotEqualityDataNulls = - new TheoryData() - { - // Valid object against null - { new Alpha8(.5F), null, typeof(Alpha8) }, - { new Argb32(Vector4.One), null, typeof(Argb32) }, - { new Bgr565(Vector3.One), null, typeof(Bgr565) }, - { new Bgra4444(Vector4.One), null, typeof(Bgra4444) }, - { new Bgra5551(Vector4.One), null, typeof(Bgra5551) }, - { new Byte4(Vector4.One * 255), null, typeof(Byte4) }, - { new HalfSingle(-1F), null, typeof(HalfSingle) }, - { new HalfVector2(0.1f, -0.3f), null, typeof(HalfVector2) }, - { new HalfVector4(Vector4.One), null, typeof(HalfVector4) }, - { new NormalizedByte2(-Vector2.One), null, typeof(NormalizedByte2) }, - { new NormalizedByte4(Vector4.One), null, typeof(NormalizedByte4) }, - { new NormalizedShort2(Vector2.One), null, typeof(NormalizedShort2) }, - { new NormalizedShort4(Vector4.One), null, typeof(NormalizedShort4) }, - { new Rg32(Vector2.One), null, typeof(Rg32) }, - { new Rgba1010102(Vector4.One), null, typeof(Rgba1010102) }, - { new Rgba64(Vector4.One), null, typeof(Rgba64) }, - { new Short2(Vector2.One * 0x7FFF), null, typeof(Short2) }, - { new Short4(Vector4.One * 0x7FFF), null, typeof(Short4) }, - }; - - public static readonly TheoryData NotEqualityDataDifferentObjects = - new TheoryData() - { - // Valid objects of different types but not equal - { new Alpha8(.5F), new Argb32(Vector4.Zero), null }, - { new HalfSingle(-1F), new NormalizedShort2(Vector2.Zero), null }, - { new Rgba1010102(Vector4.One), new Bgra5551(Vector4.Zero), null }, - }; - - public static readonly TheoryData NotEqualityData = - new TheoryData() - { - // Valid objects of the same type but not equal - { new Alpha8(.5F), new Alpha8(.8F), typeof(Alpha8) }, - { new Argb32(Vector4.One), new Argb32(Vector4.Zero), typeof(Argb32) }, - { new Bgr565(Vector3.One), new Bgr565(Vector3.Zero), typeof(Bgr565) }, - { new Bgra4444(Vector4.One), new Bgra4444(Vector4.Zero), typeof(Bgra4444) }, - { new Bgra5551(Vector4.One), new Bgra5551(Vector4.Zero), typeof(Bgra5551) }, - { new Byte4(Vector4.One * 255), new Byte4(Vector4.Zero), typeof(Byte4) }, - { new HalfSingle(-1F), new HalfSingle(1F), typeof(HalfSingle) }, - { new HalfVector2(0.1f, -0.3f), new HalfVector2(0.1f, 0.3f), typeof(HalfVector2) }, - { new HalfVector4(Vector4.One), new HalfVector4(Vector4.Zero), typeof(HalfVector4) }, - { new NormalizedByte2(-Vector2.One), new NormalizedByte2(-Vector2.Zero), typeof(NormalizedByte2) }, - { new NormalizedByte4(Vector4.One), new NormalizedByte4(Vector4.Zero), typeof(NormalizedByte4) }, - { new NormalizedShort2(Vector2.One), new NormalizedShort2(Vector2.Zero), typeof(NormalizedShort2) }, - { new NormalizedShort4(Vector4.One), new NormalizedShort4(Vector4.Zero), typeof(NormalizedShort4) }, - { new Rg32(Vector2.One), new Rg32(Vector2.Zero), typeof(Rg32) }, - { new Rgba1010102(Vector4.One), new Rgba1010102(Vector4.Zero), typeof(Rgba1010102) }, - { new Rgba32(Vector4.One), new Rgba32(Vector4.Zero), typeof(Rgba32) }, - { new Rgba64(Vector4.One), new Rgba64(Vector4.Zero), typeof(Rgba64) }, - { new Short2(Vector2.One * 0x7FFF), new Short2(Vector2.Zero), typeof(Short2) }, - { new Short4(Vector4.One * 0x7FFF), new Short4(Vector4.Zero), typeof(Short4) }, - }; - - [Theory] - [MemberData(nameof(EqualityData))] - public void Equality(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 NotEquality(object first, object second, Type type) - { - // Act - bool equal = first.Equals(second); - - // Assert - Assert.False(equal); - } - - [Theory] - [MemberData(nameof(EqualityData))] - public void HashCodeEqual(object first, object second, Type type) - { - // Act - bool equal = first.GetHashCode() == second.GetHashCode(); - - // Assert - Assert.True(equal); - } - - [Theory] - [MemberData(nameof(NotEqualityDataDifferentObjects))] - public void HashCodeNotEqual(object first, object second, Type type) - { - // Act - bool equal = first.GetHashCode() == second.GetHashCode(); - - // Assert - Assert.False(equal); - } - - [Theory] - [MemberData(nameof(EqualityData))] - public void EqualityObject(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 NotEqualityObject(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); - } - - [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 NotEqualityOperator(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); - } - } -} diff --git a/tests/ImageSharp.Tests/PixelFormats/ColorPackingTests.cs b/tests/ImageSharp.Tests/PixelFormats/ColorPackingTests.cs deleted file mode 100644 index c9a1c8fe7e..0000000000 --- a/tests/ImageSharp.Tests/PixelFormats/ColorPackingTests.cs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Collections.Generic; -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.Colors -{ - public class ColorPackingTests - { - public static IEnumerable Vector4PackData - { - get - { - Vector4[] vector4Values = new Vector4[] - { - Vector4.Zero, - Vector4.One, - Vector4.UnitX, - Vector4.UnitY, - Vector4.UnitZ, - Vector4.UnitW, - }; - - foreach (Vector4 vector4 in vector4Values) - { - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { default(Argb32), vector4Components }; - yield return new object[] { default(Bgra4444), vector4Components }; - yield return new object[] { default(Bgra5551), vector4Components }; - yield return new object[] { default(Byte4), vector4Components }; - yield return new object[] { default(HalfVector4), vector4Components }; - yield return new object[] { default(NormalizedByte4), vector4Components }; - yield return new object[] { default(NormalizedShort4), vector4Components }; - yield return new object[] { default(Rgba1010102), vector4Components }; - yield return new object[] { default(Rgba64), vector4Components }; - yield return new object[] { default(Short4), vector4Components }; - } - } - } - - public static IEnumerable Vector3PackData - { - get - { - Vector4[] vector4Values = new Vector4[] - { - Vector4.One, - new Vector4(0, 0, 0, 1), - new Vector4(1, 0, 0, 1), - new Vector4(0, 1, 0, 1), - new Vector4(0, 0, 1, 1), - }; - - foreach (Vector4 vector4 in vector4Values) - { - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { default(Argb32), vector4Components }; - yield return new object[] { new Bgr565(), vector4Components }; - } - } - } - - [Theory] - [MemberData(nameof(Vector4PackData))] - [MemberData(nameof(Vector3PackData))] - public void FromVector4ToVector4(IPixel packedVector, float[] vector4ComponentsToPack) - { - // Arrange - int precision = 2; - Vector4 vector4ToPack = new Vector4(vector4ComponentsToPack[0], vector4ComponentsToPack[1], vector4ComponentsToPack[2], vector4ComponentsToPack[3]); - packedVector.PackFromVector4(vector4ToPack); - - // Act - Vector4 vector4 = packedVector.ToVector4(); - - // Assert - Assert.Equal(vector4ToPack.X, vector4.X, precision); - Assert.Equal(vector4ToPack.Y, vector4.Y, precision); - Assert.Equal(vector4ToPack.Z, vector4.Z, precision); - Assert.Equal(vector4ToPack.W, vector4.W, precision); - } - } -} diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs index 2525ee3796..166fb230ac 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs @@ -19,193 +19,193 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(input, new Gray16(input).PackedValue); } - [Theory] - [InlineData(0)] - [InlineData(65535)] - [InlineData(32767)] - public void Gray16_ToVector4(ushort input) - { - // arrange - var gray = new Gray16(input); - - // act - var actual = gray.ToVector4(); - - // assert - Assert.Equal(input, actual.X); - Assert.Equal(input, actual.Y); - Assert.Equal(input, actual.Z); - Assert.Equal(1, actual.W); - } - - [Theory] - [InlineData(0)] - [InlineData(65535)] - [InlineData(32767)] - public void Gray16_ToScaledVector4(ushort input) - { - // arrange - var gray = new Gray16(input); - - // act - var actual = gray.ToScaledVector4(); - - // assert - float scaledInput = input / 65535f; - Assert.Equal(scaledInput, actual.X); - Assert.Equal(scaledInput, actual.Y); - Assert.Equal(scaledInput, actual.Z); - Assert.Equal(1, actual.W); - } - - [Fact] - public void Gray16_PackFromScaledVector4() - { - // arrange - Gray16 gray = default; - int expected = 32767; - Vector4 scaled = new Gray16((ushort)expected).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - ushort actual = gray.PackedValue; - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray16_PackFromScaledVector4_ToRgb24() - { - // arrange - Rgb24 actual = default; - Gray16 gray = default; - var expected = new Rgb24(128, 128, 128); - Vector4 scaled = new Gray16(32768).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray16_PackFromScaledVector4_ToRgba32() - { - // arrange - Rgba32 actual = default; - Gray16 gray = default; - var expected = new Rgba32(128, 128, 128, 255); - Vector4 scaled = new Gray16(32768).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray16_PackFromScaledVector4_ToBgr24() - { - // arrange - Bgr24 actual = default; - Gray16 gray = default; - var expected = new Bgr24(128, 128, 128); - Vector4 scaled = new Gray16(32768).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray16_PackFromScaledVector4_ToBgra32() - { - // arrange - Bgra32 actual = default; - Gray16 gray = default; - var expected = new Bgra32(128,128,128); - Vector4 scaled = new Gray16(32768).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray16_PackFromScaledVector4_ToArgb32() - { - // arrange - Gray16 gray = default; - Argb32 actual = default; - var expected = new Argb32(128, 128, 128); - Vector4 scaled = new Gray16(32768).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray16_PackFromScaledVector4_ToRgba64() - { - // arrange - Gray16 gray = default; - Rgba64 actual = default; - var expected = new Rgba64(65535, 65535, 65535, 65535); - Vector4 scaled = new Gray16(65535).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray16_PackFromRgb48_ToRgb48() - { - // arrange - var gray = default(Gray16); - var actual = default(Rgb48); - var expected = new Rgb48(0, 0, 0); - - // act - gray.PackFromRgb48(expected); - gray.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray16_PackFromRgba64_ToRgba64() - { - // arrange - var gray = default(Gray16); - var actual = default(Rgba64); - var expected = new Rgba64(0, 0, 0, 65535); - - // act - gray.PackFromRgba64(expected); - gray.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Theory] + //[InlineData(0)] + //[InlineData(65535)] + //[InlineData(32767)] + //public void Gray16_ToVector4(ushort input) + //{ + // // arrange + // var gray = new Gray16(input); + + // // act + // var actual = gray.ToVector4(); + + // // assert + // Assert.Equal(input, actual.X); + // Assert.Equal(input, actual.Y); + // Assert.Equal(input, actual.Z); + // Assert.Equal(1, actual.W); + //} + + //[Theory] + //[InlineData(0)] + //[InlineData(65535)] + //[InlineData(32767)] + //public void Gray16_ToScaledVector4(ushort input) + //{ + // // arrange + // var gray = new Gray16(input); + + // // act + // var actual = gray.ToScaledVector4(); + + // // assert + // float scaledInput = input / 65535f; + // Assert.Equal(scaledInput, actual.X); + // Assert.Equal(scaledInput, actual.Y); + // Assert.Equal(scaledInput, actual.Z); + // Assert.Equal(1, actual.W); + //} + + //[Fact] + //public void Gray16_PackFromScaledVector4() + //{ + // // arrange + // Gray16 gray = default; + // int expected = 32767; + // Vector4 scaled = new Gray16((ushort)expected).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // ushort actual = gray.PackedValue; + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray16_PackFromScaledVector4_ToRgb24() + //{ + // // arrange + // Rgb24 actual = default; + // Gray16 gray = default; + // var expected = new Rgb24(128, 128, 128); + // Vector4 scaled = new Gray16(32768).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray16_PackFromScaledVector4_ToRgba32() + //{ + // // arrange + // Rgba32 actual = default; + // Gray16 gray = default; + // var expected = new Rgba32(128, 128, 128, 255); + // Vector4 scaled = new Gray16(32768).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray16_PackFromScaledVector4_ToBgr24() + //{ + // // arrange + // Bgr24 actual = default; + // Gray16 gray = default; + // var expected = new Bgr24(128, 128, 128); + // Vector4 scaled = new Gray16(32768).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray16_PackFromScaledVector4_ToBgra32() + //{ + // // arrange + // Bgra32 actual = default; + // Gray16 gray = default; + // var expected = new Bgra32(128,128,128); + // Vector4 scaled = new Gray16(32768).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray16_PackFromScaledVector4_ToArgb32() + //{ + // // arrange + // Gray16 gray = default; + // Argb32 actual = default; + // var expected = new Argb32(128, 128, 128); + // Vector4 scaled = new Gray16(32768).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray16_PackFromScaledVector4_ToRgba64() + //{ + // // arrange + // Gray16 gray = default; + // Rgba64 actual = default; + // var expected = new Rgba64(65535, 65535, 65535, 65535); + // Vector4 scaled = new Gray16(65535).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray16_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var gray = default(Gray16); + // var actual = default(Rgb48); + // var expected = new Rgb48(0, 0, 0); + + // // act + // gray.PackFromRgb48(expected); + // gray.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray16_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var gray = default(Gray16); + // var actual = default(Rgba64); + // var expected = new Rgba64(0, 0, 0, 65535); + + // // act + // gray.PackFromRgba64(expected); + // gray.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs index 64ad0bff60..ae114a0e26 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs @@ -19,24 +19,24 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(input, new Gray8(input).PackedValue); } - [Theory] - [InlineData(0)] - [InlineData(255)] - [InlineData(30)] - public void Gray8_ToVector4(byte input) - { - // arrange - var gray = new Gray8(input); - - // act - var actual = gray.ToVector4(); - - // assert - Assert.Equal(input, actual.X); - Assert.Equal(input, actual.Y); - Assert.Equal(input, actual.Z); - Assert.Equal(1, actual.W); - } + //[Theory] + //[InlineData(0, 0)] + //[InlineData(255, 1)] + //[InlineData(30)] + //public void Gray8_ToVector4(byte input) + //{ + // // arrange + // var gray = new Gray8(input); + + // // act + // var actual = gray.ToVector4(); + + // // assert + // Assert.Equal(input, actual.X); + // Assert.Equal(input, actual.Y); + // Assert.Equal(input, actual.Z); + // Assert.Equal(1, actual.W); + //} [Theory] [InlineData(0)] @@ -74,138 +74,138 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } - [Fact] - public void Gray8_PackFromScaledVector4_ToRgb24() - { - // arrange - Rgb24 actual = default; - Gray8 gray = default; - var expected = new Rgb24(128, 128, 128); - Vector4 scaled = new Gray8(128).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray8_PackFromScaledVector4_ToRgba32() - { - // arrange - Rgba32 actual = default; - Gray8 gray = default; - var expected = new Rgba32(128, 128, 128, 255); - Vector4 scaled = new Gray8(128).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray8_PackFromScaledVector4_ToBgr24() - { - // arrange - Bgr24 actual = default; - Gray8 gray = default; - var expected = new Bgr24(128, 128, 128); - Vector4 scaled = new Gray8(128).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray8_PackFromScaledVector4_ToBgra32() - { - // arrange - Bgra32 actual = default; - Gray8 gray = default; - var expected = new Bgra32(128,128,128); - Vector4 scaled = new Gray8(128).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray8_PackFromScaledVector4_ToArgb32() - { - // arrange - Gray8 gray = default; - Argb32 actual = default; - var expected = new Argb32(128, 128, 128); - Vector4 scaled = new Gray8(128).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray8_PackFromScaledVector4_ToRgba64() - { - // arrange - Gray8 gray = default; - Rgba64 actual = default; - var expected = new Rgba64(65535, 65535, 65535, 65535); - Vector4 scaled = new Gray8(255).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray8_PackFromRgb48_ToRgb48() - { - // arrange - var gray = default(Gray8); - var actual = default(Rgb48); - var expected = new Rgb48(0, 0, 0); - - // act - gray.PackFromRgb48(expected); - gray.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray8_PackFromRgba64_ToRgba64() - { - // arrange - var gray = default(Gray8); - var actual = default(Rgba64); - var expected = new Rgba64(0, 0, 0, 65535); - - // act - gray.PackFromRgba64(expected); - gray.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void Gray8_PackFromScaledVector4_ToRgb24() + //{ + // // arrange + // Rgb24 actual = default; + // Gray8 gray = default; + // var expected = new Rgb24(128, 128, 128); + // Vector4 scaled = new Gray8(128).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray8_PackFromScaledVector4_ToRgba32() + //{ + // // arrange + // Rgba32 actual = default; + // Gray8 gray = default; + // var expected = new Rgba32(128, 128, 128, 255); + // Vector4 scaled = new Gray8(128).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray8_PackFromScaledVector4_ToBgr24() + //{ + // // arrange + // Bgr24 actual = default; + // Gray8 gray = default; + // var expected = new Bgr24(128, 128, 128); + // Vector4 scaled = new Gray8(128).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray8_PackFromScaledVector4_ToBgra32() + //{ + // // arrange + // Bgra32 actual = default; + // Gray8 gray = default; + // var expected = new Bgra32(128,128,128); + // Vector4 scaled = new Gray8(128).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray8_PackFromScaledVector4_ToArgb32() + //{ + // // arrange + // Gray8 gray = default; + // Argb32 actual = default; + // var expected = new Argb32(128, 128, 128); + // Vector4 scaled = new Gray8(128).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray8_PackFromScaledVector4_ToRgba64() + //{ + // // arrange + // Gray8 gray = default; + // Rgba64 actual = default; + // var expected = new Rgba64(65535, 65535, 65535, 65535); + // Vector4 scaled = new Gray8(255).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray8_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var gray = default(Gray8); + // var actual = default(Rgb48); + // var expected = new Rgb48(0, 0, 0); + + // // act + // gray.PackFromRgb48(expected); + // gray.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray8_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var gray = default(Gray8); + // var actual = default(Rgba64); + // var expected = new Rgba64(0, 0, 0, 65535); + + // // act + // gray.PackFromRgba64(expected); + // gray.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs index 3376645f34..1c3905854e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs @@ -67,111 +67,111 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } - [Fact] - public void HalfSingle_ToRgb24() - { - // arrange - var halfVector = new HalfSingle(.5F); - var actual = default(Rgb24); - var expected = new Rgb24(128, 0, 0); - - // act - halfVector.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_Rgba32() - { - // arrange - var halfVector = new HalfSingle(.5F); - var actual = default(Rgba32); - var expected = new Rgba32(128, 0, 0, 255); - - // act - halfVector.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_ToBgr24() - { - // arrange - var halfVector = new HalfSingle(.5F); - var actual = default(Bgr24); - var expected = new Bgr24(128, 0, 0); - - // act - halfVector.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_Bgra32() - { - // arrange - var halfVector = new HalfSingle(.5F); - var actual = default(Bgra32); - var expected = new Bgra32(128, 0, 0, 255); - - // act - halfVector.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_Argb32() - { - // arrange - var halfVector = new HalfSingle(.5F); - var actual = default(Argb32); - var expected = new Argb32(128, 0, 0, 255); - - // act - halfVector.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(HalfSingle); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(HalfSingle); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void HalfSingle_ToRgb24() + //{ + // // arrange + // var halfVector = new HalfSingle(.5F); + // var actual = default(Rgb24); + // var expected = new Rgb24(128, 0, 0); + + // // act + // halfVector.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfSingle_Rgba32() + //{ + // // arrange + // var halfVector = new HalfSingle(.5F); + // var actual = default(Rgba32); + // var expected = new Rgba32(128, 0, 0, 255); + + // // act + // halfVector.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfSingle_ToBgr24() + //{ + // // arrange + // var halfVector = new HalfSingle(.5F); + // var actual = default(Bgr24); + // var expected = new Bgr24(128, 0, 0); + + // // act + // halfVector.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfSingle_Bgra32() + //{ + // // arrange + // var halfVector = new HalfSingle(.5F); + // var actual = default(Bgra32); + // var expected = new Bgra32(128, 0, 0, 255); + + // // act + // halfVector.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfSingle_Argb32() + //{ + // // arrange + // var halfVector = new HalfSingle(.5F); + // var actual = default(Argb32); + // var expected = new Argb32(128, 0, 0, 255); + + // // act + // halfVector.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfSingle_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(HalfSingle); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 0, 0); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfSingle_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(HalfSingle); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 0, 0, 65535); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs index c2a524f0dc..1ceb224e5e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs @@ -72,111 +72,111 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } - [Fact] - public void HalfVector2_ToRgb24() - { - // arrange - var halfVector = new HalfVector2(.5F, .25F); - var actual = default(Rgb24); - var expected = new Rgb24(128, 64, 0); - - // act - halfVector.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_Rgba32() - { - // arrange - var halfVector = new HalfVector2(.5F, .25F); - var actual = default(Rgba32); - var expected = new Rgba32(128, 64, 0, 255); - - // act - halfVector.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_ToBgr24() - { - // arrange - var halfVector = new HalfVector2(.5F, .25F); - var actual = default(Bgr24); - var expected = new Bgr24(128, 64, 0); - - // act - halfVector.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_Bgra32() - { - // arrange - var halfVector = new HalfVector2(.5F, .25F); - var actual = default(Bgra32); - var expected = new Bgra32(128, 64, 0, 255); - - // act - halfVector.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_Argb32() - { - // arrange - var halfVector = new HalfVector2(.5F, .25F); - var actual = default(Argb32); - var expected = new Argb32(128, 64, 0, 255); - - // act - halfVector.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(HalfVector2); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(HalfVector2); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void HalfVector2_ToRgb24() + //{ + // // arrange + // var halfVector = new HalfVector2(.5F, .25F); + // var actual = default(Rgb24); + // var expected = new Rgb24(128, 64, 0); + + // // act + // halfVector.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector2_Rgba32() + //{ + // // arrange + // var halfVector = new HalfVector2(.5F, .25F); + // var actual = default(Rgba32); + // var expected = new Rgba32(128, 64, 0, 255); + + // // act + // halfVector.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector2_ToBgr24() + //{ + // // arrange + // var halfVector = new HalfVector2(.5F, .25F); + // var actual = default(Bgr24); + // var expected = new Bgr24(128, 64, 0); + + // // act + // halfVector.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector2_Bgra32() + //{ + // // arrange + // var halfVector = new HalfVector2(.5F, .25F); + // var actual = default(Bgra32); + // var expected = new Bgra32(128, 64, 0, 255); + + // // act + // halfVector.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector2_Argb32() + //{ + // // arrange + // var halfVector = new HalfVector2(.5F, .25F); + // var actual = default(Argb32); + // var expected = new Argb32(128, 64, 0, 255); + + // // act + // halfVector.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector2_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(HalfVector2); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 65535, 0); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector2_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(HalfVector2); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 65535, 0, 65535); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs index 8b28dd8277..3ba5718503 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs @@ -66,159 +66,159 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } - [Fact] - public void HalfVector4_ToRgb24() - { - // arrange - var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - var actual = default(Rgb24); - var expected = new Rgb24(64, 128, 191); - - // act - halfVector.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_Rgba32() - { - // arrange - var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - var actual = default(Rgba32); - var expected = new Rgba32(64, 128, 191, 255); - - // act - halfVector.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_ToBgr24() - { - // arrange - var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - var actual = default(Bgr24); - var expected = new Bgr24(64, 128, 191); - - // act - halfVector.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_Bgra32() - { - // arrange - var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - var actual = default(Bgra32); - var expected = new Bgra32(64, 128, 191, 255); - - // act - halfVector.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_Argb32() - { - // arrange - var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - var actual = default(Argb32); - var expected = new Argb32(64, 128, 191, 255); - - // act - halfVector.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_PackFromRgba32_ToRgba32() - { - // arrange - var halVector = default(HalfVector4); - var actual = default(Rgba32); - var expected = new Rgba32(64, 128, 191, 255); - - // act - halVector.PackFromRgba32(expected); - halVector.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_PackFromBgra32_ToBgra32() - { - // arrange - var halVector = default(HalfVector4); - var actual = default(Bgra32); - var expected = new Bgra32(64, 128, 191, 255); - - // act - halVector.PackFromBgra32(expected); - halVector.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_PackFromArgb32_ToArgb32() - { - // arrange - var halVector = default(HalfVector4); - var actual = default(Argb32); - var expected = new Argb32(64, 128, 191, 255); - - // act - halVector.PackFromArgb32(expected); - halVector.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(HalfVector4); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(HalfVector4); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void HalfVector4_ToRgb24() + //{ + // // arrange + // var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); + // var actual = default(Rgb24); + // var expected = new Rgb24(64, 128, 191); + + // // act + // halfVector.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector4_Rgba32() + //{ + // // arrange + // var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); + // var actual = default(Rgba32); + // var expected = new Rgba32(64, 128, 191, 255); + + // // act + // halfVector.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector4_ToBgr24() + //{ + // // arrange + // var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); + // var actual = default(Bgr24); + // var expected = new Bgr24(64, 128, 191); + + // // act + // halfVector.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector4_Bgra32() + //{ + // // arrange + // var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); + // var actual = default(Bgra32); + // var expected = new Bgra32(64, 128, 191, 255); + + // // act + // halfVector.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector4_Argb32() + //{ + // // arrange + // var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); + // var actual = default(Argb32); + // var expected = new Argb32(64, 128, 191, 255); + + // // act + // halfVector.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector4_PackFromRgba32_ToRgba32() + //{ + // // arrange + // var halVector = default(HalfVector4); + // var actual = default(Rgba32); + // var expected = new Rgba32(64, 128, 191, 255); + + // // act + // halVector.PackFromRgba32(expected); + // halVector.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector4_PackFromBgra32_ToBgra32() + //{ + // // arrange + // var halVector = default(HalfVector4); + // var actual = default(Bgra32); + // var expected = new Bgra32(64, 128, 191, 255); + + // // act + // halVector.PackFromBgra32(expected); + // halVector.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector4_PackFromArgb32_ToArgb32() + //{ + // // arrange + // var halVector = default(HalfVector4); + // var actual = default(Argb32); + // var expected = new Argb32(64, 128, 191, 255); + + // // act + // halVector.PackFromArgb32(expected); + // halVector.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector4_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(HalfVector4); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 0, 65535); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector4_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(HalfVector4); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 0, 65535, 0); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs index 83f22e2aa0..3ab36853b9 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs @@ -67,127 +67,127 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } - [Fact] - public void NormalizedByte2_PackFromRgba32() - { - // arrange - var byte2 = new NormalizedByte2(); - var rgba = new Rgba32(141, 90, 0, 0); - int expected = 0xda0d; - - // act - byte2.PackFromRgba32(rgba); - ushort actual = byte2.PackedValue; - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_ToRgb24() - { - // arrange - var short4 = new NormalizedByte2(0.1f, -0.3f); - var actual = default(Rgb24); - var expected = new Rgb24(141, 90, 0); - - // act - short4.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_ToRgba32() - { - // arrange - var short4 = new NormalizedByte2(0.1f, -0.3f); - var actual = default(Rgba32); - var expected = new Rgba32(141, 90, 0, 255); - - // act - short4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_ToBgr24() - { - // arrange - var short4 = new NormalizedByte2(0.1f, -0.3f); - var actual = default(Bgr24); - var expected = new Bgr24(141, 90, 0); - - // act - short4.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_ToBgra32() - { - // arrange - var short4 = new NormalizedByte2(0.1f, -0.3f); - var actual = default(Bgra32); - var expected = new Bgra32(141, 90, 0, 255); - - // act - short4.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_ToArgb32() - { - // arrange - var short4 = new NormalizedByte2(0.1f, -0.3f); - var actual = default(Argb32); - var expected = new Argb32(141, 90, 0, 255); - - // act - short4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(NormalizedByte2); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(NormalizedByte2); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void NormalizedByte2_PackFromRgba32() + //{ + // // arrange + // var byte2 = new NormalizedByte2(); + // var rgba = new Rgba32(141, 90, 0, 0); + // int expected = 0xda0d; + + // // act + // byte2.PackFromRgba32(rgba); + // ushort actual = byte2.PackedValue; + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte2_ToRgb24() + //{ + // // arrange + // var short4 = new NormalizedByte2(0.1f, -0.3f); + // var actual = default(Rgb24); + // var expected = new Rgb24(141, 90, 0); + + // // act + // short4.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte2_ToRgba32() + //{ + // // arrange + // var short4 = new NormalizedByte2(0.1f, -0.3f); + // var actual = default(Rgba32); + // var expected = new Rgba32(141, 90, 0, 255); + + // // act + // short4.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte2_ToBgr24() + //{ + // // arrange + // var short4 = new NormalizedByte2(0.1f, -0.3f); + // var actual = default(Bgr24); + // var expected = new Bgr24(141, 90, 0); + + // // act + // short4.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte2_ToBgra32() + //{ + // // arrange + // var short4 = new NormalizedByte2(0.1f, -0.3f); + // var actual = default(Bgra32); + // var expected = new Bgra32(141, 90, 0, 255); + + // // act + // short4.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte2_ToArgb32() + //{ + // // arrange + // var short4 = new NormalizedByte2(0.1f, -0.3f); + // var actual = default(Argb32); + // var expected = new Argb32(141, 90, 0, 255); + + // // act + // short4.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte2_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(NormalizedByte2); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 65535, 0); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte2_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(NormalizedByte2); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 65535, 0, 65535); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs index 16516496f8..acac04853f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs @@ -61,144 +61,144 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } - [Fact] - public void NormalizedByte4_ToRgb24() - { - // arrange - var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(141, 90, 192); - - // act - short4.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_ToRgba32() - { - // arrange - var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(141, 90, 192, 39); - - // act - short4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_ToBgr24() - { - // arrange - var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(141, 90, 192); - - // act - short4.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_ToArgb32() - { - // arrange - var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(141, 90, 192, 39); - - // act - short4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_PackFromRgba32_ToRgba32() - { - // arrange - var short4 = default(NormalizedByte4); - var actual = default(Rgba32); - var expected = new Rgba32(9, 115, 202, 127); - - // act - short4.PackFromRgba32(new Rgba32(9, 115, 202, 127)); - short4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_PackFromBgra32_ToRgba32() - { - // arrange - var actual = default(Bgra32); - var short4 = default(NormalizedByte4); - var expected = new Bgra32(9, 115, 202, 127); - - // act - short4.PackFromBgra32(expected); - short4.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_PackFromArgb32_ToRgba32() - { - // arrange - var short4 = default(NormalizedByte4); - var actual = default(Argb32); - var expected = new Argb32(9, 115, 202, 127); - - // act - short4.PackFromArgb32(expected); - short4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(NormalizedByte4); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(NormalizedByte4); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void NormalizedByte4_ToRgb24() + //{ + // // arrange + // var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Rgb24); + // var expected = new Rgb24(141, 90, 192); + + // // act + // short4.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte4_ToRgba32() + //{ + // // arrange + // var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Rgba32); + // var expected = new Rgba32(141, 90, 192, 39); + + // // act + // short4.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte4_ToBgr24() + //{ + // // arrange + // var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Bgr24); + // var expected = new Bgr24(141, 90, 192); + + // // act + // short4.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte4_ToArgb32() + //{ + // // arrange + // var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Argb32); + // var expected = new Argb32(141, 90, 192, 39); + + // // act + // short4.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte4_PackFromRgba32_ToRgba32() + //{ + // // arrange + // var short4 = default(NormalizedByte4); + // var actual = default(Rgba32); + // var expected = new Rgba32(9, 115, 202, 127); + + // // act + // short4.PackFromRgba32(new Rgba32(9, 115, 202, 127)); + // short4.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte4_PackFromBgra32_ToRgba32() + //{ + // // arrange + // var actual = default(Bgra32); + // var short4 = default(NormalizedByte4); + // var expected = new Bgra32(9, 115, 202, 127); + + // // act + // short4.PackFromBgra32(expected); + // short4.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte4_PackFromArgb32_ToRgba32() + //{ + // // arrange + // var short4 = default(NormalizedByte4); + // var actual = default(Argb32); + // var expected = new Argb32(9, 115, 202, 127); + + // // act + // short4.PackFromArgb32(expected); + // short4.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte4_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(NormalizedByte4); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 65535, 0); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte4_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(NormalizedByte4); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 65535, 0, 65535); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs index 2fb7f05aca..e02d513c2a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs @@ -70,128 +70,128 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } - [Fact] - public void NormalizedShort2_PackFromRgba32_ToRgb24() - { - // arrange - var actual = default(Rgb24); - var short2 = new NormalizedShort2(); - var rgba = new Rgba32(141, 90, 0, 0); - var expected = new Rgb24(141, 90, 0); - - // act - short2.PackFromRgba32(rgba); - short2.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_ToRgb24() - { - // arrange - var short2 = new NormalizedShort2(0.1f, -0.3f); - var actual = default(Rgb24); - var expected = new Rgb24(141, 90, 0); - - // act - short2.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_ToRgba32() - { - // arrange - var short2 = new NormalizedShort2(0.1f, -0.3f); - var actual = default(Rgba32); - var expected = new Rgba32(141, 90, 0, 255); - - // act - short2.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_ToBgr24() - { - // arrange - var short2 = new NormalizedShort2(0.1f, -0.3f); - var actual = default(Bgr24); - var expected = new Bgr24(141, 90, 0); - - // act - short2.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_ToBgra32() - { - // arrange - var short2 = new NormalizedShort2(0.1f, -0.3f); - var actual = default(Bgra32); - var expected = new Bgra32(141, 90, 0, 255); - - // act - short2.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_ToArgb32() - { - // arrange - var short2 = new NormalizedShort2(0.1f, -0.3f); - var actual = default(Argb32); - var expected = new Argb32(141, 90, 0, 255); - - // act - short2.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(NormalizedShort2); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(NormalizedShort2); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void NormalizedShort2_PackFromRgba32_ToRgb24() + //{ + // // arrange + // var actual = default(Rgb24); + // var short2 = new NormalizedShort2(); + // var rgba = new Rgba32(141, 90, 0, 0); + // var expected = new Rgb24(141, 90, 0); + + // // act + // short2.PackFromRgba32(rgba); + // short2.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort2_ToRgb24() + //{ + // // arrange + // var short2 = new NormalizedShort2(0.1f, -0.3f); + // var actual = default(Rgb24); + // var expected = new Rgb24(141, 90, 0); + + // // act + // short2.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort2_ToRgba32() + //{ + // // arrange + // var short2 = new NormalizedShort2(0.1f, -0.3f); + // var actual = default(Rgba32); + // var expected = new Rgba32(141, 90, 0, 255); + + // // act + // short2.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort2_ToBgr24() + //{ + // // arrange + // var short2 = new NormalizedShort2(0.1f, -0.3f); + // var actual = default(Bgr24); + // var expected = new Bgr24(141, 90, 0); + + // // act + // short2.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort2_ToBgra32() + //{ + // // arrange + // var short2 = new NormalizedShort2(0.1f, -0.3f); + // var actual = default(Bgra32); + // var expected = new Bgra32(141, 90, 0, 255); + + // // act + // short2.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort2_ToArgb32() + //{ + // // arrange + // var short2 = new NormalizedShort2(0.1f, -0.3f); + // var actual = default(Argb32); + // var expected = new Argb32(141, 90, 0, 255); + + // // act + // short2.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort2_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(NormalizedShort2); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 65535, 0); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort2_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(NormalizedShort2); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 65535, 0, 65535); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs index 7dcdd9c88b..25ffbb348a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs @@ -62,144 +62,144 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } - [Fact] - public void NormalizedShort4_ToRgb24() - { - // arrange - var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(141, 90, 192); - - // act - short4.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_ToRgba32() - { - // arrange - var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(141, 90, 192, 39); - - // act - short4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_ToBgr24() - { - // arrange - var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(141, 90, 192); - - // act - short4.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_ToArgb32() - { - // arrange - var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(141, 90, 192, 39); - - // act - short4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_PackFromRgba32_ToRgba32() - { - // arrange - var short4 = default(NormalizedShort4); - var expected = new Rgba32(9, 115, 202, 127); - var actual = default(Rgba32); - - // act - short4.PackFromRgba32(expected); - short4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_PackFromBgra32_ToRgba32() - { - // arrange - var short4 = default(NormalizedShort4); - var actual = default(Bgra32); - var expected = new Bgra32(9, 115, 202, 127); - - // act - short4.PackFromBgra32(expected); - short4.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_PackFromArgb32_ToRgba32() - { - // arrange - var short4 = default(NormalizedShort4); - var actual = default(Argb32); - var expected = new Argb32(9, 115, 202, 127); - - // act - short4.PackFromArgb32(expected); - short4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(NormalizedShort4); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(NormalizedShort4); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void NormalizedShort4_ToRgb24() + //{ + // // arrange + // var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Rgb24); + // var expected = new Rgb24(141, 90, 192); + + // // act + // short4.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort4_ToRgba32() + //{ + // // arrange + // var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Rgba32); + // var expected = new Rgba32(141, 90, 192, 39); + + // // act + // short4.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort4_ToBgr24() + //{ + // // arrange + // var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Bgr24); + // var expected = new Bgr24(141, 90, 192); + + // // act + // short4.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort4_ToArgb32() + //{ + // // arrange + // var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Argb32); + // var expected = new Argb32(141, 90, 192, 39); + + // // act + // short4.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort4_PackFromRgba32_ToRgba32() + //{ + // // arrange + // var short4 = default(NormalizedShort4); + // var expected = new Rgba32(9, 115, 202, 127); + // var actual = default(Rgba32); + + // // act + // short4.PackFromRgba32(expected); + // short4.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort4_PackFromBgra32_ToRgba32() + //{ + // // arrange + // var short4 = default(NormalizedShort4); + // var actual = default(Bgra32); + // var expected = new Bgra32(9, 115, 202, 127); + + // // act + // short4.PackFromBgra32(expected); + // short4.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort4_PackFromArgb32_ToRgba32() + //{ + // // arrange + // var short4 = default(NormalizedShort4); + // var actual = default(Argb32); + // var expected = new Argb32(9, 115, 202, 127); + + // // act + // short4.PackFromArgb32(expected); + // short4.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort4_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(NormalizedShort4); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 65535, 0); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort4_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(NormalizedShort4); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 65535, 0, 65535); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 9e41fd94f3..92b04f587e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -1,95 +1,89 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Buffers; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; -using Xunit.Abstractions; - -namespace SixLabors.ImageSharp.Tests.PixelFormats -{ - public partial class PixelOperationsTests - { - public class Rgba32 : PixelOperationsTests - { - public Rgba32(ITestOutputHelper output) - : base(output) - { - } - - // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - - [Fact] - public void IsSpecialImplementation() - { - Assert.IsType(PixelOperations.Instance); - } - - [Fact] - public void ToVector4SimdAligned() - { - if (!Vector.IsHardwareAccelerated) - { - return; - } - - ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(64); - Vector4[] expected = CreateExpectedVector4Data(source); - - TestOperation( - source, - expected, - (s, d) => ImageSharp.PixelFormats.Rgba32.PixelOperations.ToVector4SimdAligned(s, d.GetSpan(), 64) - ); - } - - - // [Fact] // Profiling benchmark - enable manually! -#pragma warning disable xUnit1013 // Public method should be marked as test - public void Benchmark_ToVector4() -#pragma warning restore xUnit1013 // Public method should be marked as test - { - int times = 200000; - int count = 1024; - - using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) - using (IMemoryOwner dest = Configuration.Default.MemoryAllocator.Allocate(count)) - { - this.Measure( - times, - () => - { - PixelOperations.Instance.ToVector4(source.GetSpan(), dest.GetSpan(), count); - }); - } - } - } - - public class Argb32 : PixelOperationsTests - { - // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: - public Argb32(ITestOutputHelper output) - : base(output) - { - } - - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - } - - [Theory] - [WithBlankImages(1, 1, PixelTypes.All)] - public void GetGlobalInstance(TestImageProvider dummy) - where TPixel : struct, IPixel - { - Assert.NotNull(PixelOperations.Instance); +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats +{ + public partial class PixelOperationsTests + { + public class Rgba32 : PixelOperationsTests + { + public Rgba32(ITestOutputHelper output) + : base(output) + { + } + + // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + + [Fact] + public void ToVector4SimdAligned() + { + if (!Vector.IsHardwareAccelerated) + { + return; + } + + ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(64); + Vector4[] expected = CreateExpectedVector4Data(source); + + TestOperation( + source, + expected, + (s, d) => ImageSharp.PixelFormats.Rgba32.PixelOperations.ToVector4SimdAligned(s, d.GetSpan(), 64) + ); + } + + + // [Fact] // Profiling benchmark - enable manually! +#pragma warning disable xUnit1013 // Public method should be marked as test + public void Benchmark_ToVector4() +#pragma warning restore xUnit1013 // Public method should be marked as test + { + int times = 200000; + int count = 1024; + + using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) + using (IMemoryOwner dest = Configuration.Default.MemoryAllocator.Allocate(count)) + { + this.Measure( + times, + () => + { + PixelOperations.Instance.ToVector4(source.GetSpan(), dest.GetSpan(), count); + }); + } + } } + public class Argb32 : PixelOperationsTests + { + // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: + public Argb32(ITestOutputHelper output) + : base(output) + { + } + + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + } + + [Theory] + [WithBlankImages(1, 1, PixelTypes.All)] + public void GetGlobalInstance(TestImageProvider dummy) + where TPixel : struct, IPixel => Assert.NotNull(PixelOperations.Instance); + [Fact] public void IsOpaqueColor() { @@ -98,595 +92,593 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.False(new GraphicsOptions(true, 0.5f).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); Assert.False(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Transparent)); Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Lighten, 1).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); - Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal,PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); - } - } - - public abstract class PixelOperationsTests : MeasureFixture - where TPixel : struct, IPixel - { - protected PixelOperationsTests(ITestOutputHelper output) - : base(output) - { - } - - public static TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - - private static PixelOperations Operations => PixelOperations.Instance; - - internal static TPixel[] CreateExpectedPixelData(Vector4[] source) - { - var expected = new TPixel[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i].PackFromVector4(source[i]); - } - return expected; - } - - internal static TPixel[] CreateScaledExpectedPixelData(Vector4[] source) - { - var expected = new TPixel[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i].PackFromScaledVector4(source[i]); - } - return expected; - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromVector4(int count) - { - Vector4[] source = CreateVector4TestData(count); - TPixel[] expected = CreateExpectedPixelData(source); - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromVector4(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromScaledVector4(int count) - { - Vector4[] source = CreateVector4TestData(count); - TPixel[] expected = CreateScaledExpectedPixelData(source); - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromScaledVector4(s, d.GetSpan(), count) - ); - } - - internal static Vector4[] CreateExpectedVector4Data(TPixel[] source) - { - var expected = new Vector4[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i] = source[i].ToVector4(); - } - return expected; - } - - internal static Vector4[] CreateExpectedScaledVector4Data(TPixel[] source) - { - var expected = new Vector4[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i] = source[i].ToScaledVector4(); - } - return expected; - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToVector4(int count) - { - TPixel[] source = CreatePixelTestData(count); - Vector4[] expected = CreateExpectedVector4Data(source); - - TestOperation( - source, - expected, - (s, d) => Operations.ToVector4(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToScaledVector4(int count) - { - TPixel[] source = CreateScaledPixelTestData(count); - Vector4[] expected = CreateExpectedScaledVector4Data(source); - - TestOperation( - source, - expected, - (s, d) => Operations.ToScaledVector4(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromRgb24Bytes(int count) - { - byte[] source = CreateByteTestData(count * 3); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i3 = i * 3; - - expected[i].PackFromRgba32(new Rgba32(source[i3 + 0], source[i3 + 1], source[i3 + 2], 255)); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromRgb24Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToRgb24Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 3]; - var rgb = default(Rgb24); - - for (int i = 0; i < count; i++) - { - int i3 = i * 3; - source[i].ToRgb24(ref rgb); - expected[i3] = rgb.R; - expected[i3 + 1] = rgb.G; - expected[i3 + 2] = rgb.B; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToRgb24Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromRgba32Bytes(int count) - { - byte[] source = CreateByteTestData(count * 4); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - - expected[i].PackFromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromRgba32Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToRgba32Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var rgba = default(Rgba32); - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - source[i].ToRgba32(ref rgba); - expected[i4] = rgba.R; - expected[i4 + 1] = rgba.G; - expected[i4 + 2] = rgba.B; - expected[i4 + 3] = rgba.A; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToRgba32Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromRgb48Bytes(int count) - { - byte[] source = CreateByteTestData(count * 6); - Span sourceSpan = source.AsSpan(); - var expected = new TPixel[count]; - - var rgba64 = new Rgba64(0, 0, 0, 65535); - for (int i = 0; i < count; i++) - { - int i6 = i * 6; - rgba64.Rgb = MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]; - expected[i].PackFromRgba64(rgba64); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromRgb48Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToRgb48Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 6]; - Rgb48 rgb = default; - - for (int i = 0; i < count; i++) - { - int i6 = i * 6; - source[i].ToRgb48(ref rgb); - Rgba64Bytes rgb48Bytes = Unsafe.As(ref rgb); - expected[i6] = rgb48Bytes[0]; - expected[i6 + 1] = rgb48Bytes[1]; - expected[i6 + 2] = rgb48Bytes[2]; - expected[i6 + 3] = rgb48Bytes[3]; - expected[i6 + 4] = rgb48Bytes[4]; - expected[i6 + 5] = rgb48Bytes[5]; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToRgb48Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromRgba64Bytes(int count) - { - byte[] source = CreateByteTestData(count * 8); - Span sourceSpan = source.AsSpan(); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i8 = i * 8; - expected[i].PackFromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromRgba64Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToRgba64Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 8]; - Rgba64 rgba = default; - - for (int i = 0; i < count; i++) - { - int i8 = i * 8; - source[i].ToRgba64(ref rgba); - Rgba64Bytes rgba64Bytes = Unsafe.As(ref rgba); - expected[i8] = rgba64Bytes[0]; - expected[i8 + 1] = rgba64Bytes[1]; - expected[i8 + 2] = rgba64Bytes[2]; - expected[i8 + 3] = rgba64Bytes[3]; - expected[i8 + 4] = rgba64Bytes[4]; - expected[i8 + 5] = rgba64Bytes[5]; - expected[i8 + 6] = rgba64Bytes[6]; - expected[i8 + 7] = rgba64Bytes[7]; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToRgba64Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromBgr24Bytes(int count) - { - byte[] source = CreateByteTestData(count * 3); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i3 = i * 3; - - expected[i].PackFromRgba32(new Rgba32(source[i3 + 2], source[i3 + 1], source[i3 + 0], 255)); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromBgr24Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToBgr24Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 3]; - var bgr = default(Bgr24); - - for (int i = 0; i < count; i++) - { - int i3 = i * 3; - source[i].ToBgr24(ref bgr); - expected[i3] = bgr.B; - expected[i3 + 1] = bgr.G; - expected[i3 + 2] = bgr.R; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToBgr24Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromBgra32Bytes(int count) - { - byte[] source = CreateByteTestData(count * 4); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - - expected[i].PackFromRgba32(new Rgba32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromBgra32Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToZyxwBytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var bgra = default(Bgra32); - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - source[i].ToBgra32(ref bgra); - expected[i4] = bgra.B; - expected[i4 + 1] = bgra.G; - expected[i4 + 2] = bgra.R; - expected[i4 + 3] = bgra.A; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToBgra32Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromArgb32Bytes(int count) - { - byte[] source = CreateByteTestData(count * 4); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - - expected[i].PackFromRgba32(new Rgba32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromArgb32Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToArgb32Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var argb = default(Argb32); - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - source[i].ToArgb32(ref argb); - expected[i4] = argb.A; - expected[i4 + 1] = argb.R; - expected[i4 + 2] = argb.G; - expected[i4 + 3] = argb.B; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToArgb32Bytes(s, d.GetSpan(), count) - ); - } - - private class TestBuffers : IDisposable - where TSource : struct - where TDest : struct - { - public TSource[] SourceBuffer { get; } - public IMemoryOwner ActualDestBuffer { get; } - public TDest[] ExpectedDestBuffer { get; } - - public TestBuffers(TSource[] source, TDest[] expectedDest) - { - this.SourceBuffer = source; - this.ExpectedDestBuffer = expectedDest; - this.ActualDestBuffer = Configuration.Default.MemoryAllocator.Allocate(expectedDest.Length); - } - - public void Dispose() - { - this.ActualDestBuffer.Dispose(); - } - - private const float Tolerance = 0.0001f; - - public void Verify() - { - int count = this.ExpectedDestBuffer.Length; - - if (typeof(TDest) == typeof(Vector4)) - { - - Span expected = MemoryMarshal.Cast(this.ExpectedDestBuffer.AsSpan()); - Span actual = MemoryMarshal.Cast(this.ActualDestBuffer.GetSpan()); - - for (int i = 0; i < count; i++) - { - // ReSharper disable PossibleNullReferenceException - Assert.Equal(expected[i], actual[i], new ApproximateFloatComparer(0.001f)); - // ReSharper restore PossibleNullReferenceException - } - } - else - { - Span expected = this.ExpectedDestBuffer.AsSpan(); - Span actual = this.ActualDestBuffer.GetSpan(); - for (int i = 0; i < count; i++) - { - Assert.Equal(expected[i], actual[i]); - } - } - } - } - - internal static void TestOperation( - TSource[] source, - TDest[] expected, - Action> action) - where TSource : struct - where TDest : struct - { - using (var buffers = new TestBuffers(source, expected)) - { - action(buffers.SourceBuffer, buffers.ActualDestBuffer); - buffers.Verify(); - } - } - - internal static Vector4[] CreateVector4TestData(int length) - { - var result = new Vector4[length]; - var rnd = new Random(42); // Deterministic random values - - for (int i = 0; i < result.Length; i++) - { - result[i] = GetVector(rnd); - } - return result; - } - - internal static TPixel[] CreatePixelTestData(int length) - { - var result = new TPixel[length]; - - var rnd = new Random(42); // Deterministic random values - - for (int i = 0; i < result.Length; i++) - { - Vector4 v = GetVector(rnd); - result[i].PackFromVector4(v); - } - - return result; - } - - internal static TPixel[] CreateScaledPixelTestData(int length) - { - var result = new TPixel[length]; - - var rnd = new Random(42); // Deterministic random values - - for (int i = 0; i < result.Length; i++) - { - Vector4 v = GetVector(rnd); - result[i].PackFromScaledVector4(v); - } - - return result; - } - - internal static byte[] CreateByteTestData(int length) - { - byte[] result = new byte[length]; - var rnd = new Random(42); // Deterministic random values - - for (int i = 0; i < result.Length; i++) - { - result[i] = (byte)rnd.Next(255); - } - return result; - } - - internal static Vector4 GetVector(Random rnd) - { - return new Vector4( - (float)rnd.NextDouble(), - (float)rnd.NextDouble(), - (float)rnd.NextDouble(), - (float)rnd.NextDouble() - ); - } - - [StructLayout(LayoutKind.Sequential)] - private unsafe struct Rgba64Bytes - { - public fixed byte Data[8]; - - public byte this[int idx] - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - ref byte self = ref Unsafe.As(ref this); - return Unsafe.Add(ref self, idx); - } - } - } - } + Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); + } + } + + public abstract class PixelOperationsTests : MeasureFixture + where TPixel : struct, IPixel + { + protected PixelOperationsTests(ITestOutputHelper output) + : base(output) + { + } + + public static TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + private static PixelOperations Operations => PixelOperations.Instance; + + internal static TPixel[] CreateExpectedPixelData(Vector4[] source) + { + var expected = new TPixel[source.Length]; + + for (int i = 0; i < expected.Length; i++) + { + expected[i].PackFromVector4(source[i]); + } + return expected; + } + + internal static TPixel[] CreateScaledExpectedPixelData(Vector4[] source) + { + var expected = new TPixel[source.Length]; + + for (int i = 0; i < expected.Length; i++) + { + expected[i].PackFromScaledVector4(source[i]); + } + return expected; + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromVector4(int count) + { + Vector4[] source = CreateVector4TestData(count); + TPixel[] expected = CreateExpectedPixelData(source); + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromVector4(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromScaledVector4(int count) + { + Vector4[] source = CreateVector4TestData(count); + TPixel[] expected = CreateScaledExpectedPixelData(source); + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromScaledVector4(s, d.GetSpan(), count) + ); + } + + internal static Vector4[] CreateExpectedVector4Data(TPixel[] source) + { + var expected = new Vector4[source.Length]; + + for (int i = 0; i < expected.Length; i++) + { + expected[i] = source[i].ToVector4(); + } + return expected; + } + + internal static Vector4[] CreateExpectedScaledVector4Data(TPixel[] source) + { + var expected = new Vector4[source.Length]; + + for (int i = 0; i < expected.Length; i++) + { + expected[i] = source[i].ToScaledVector4(); + } + return expected; + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToVector4(int count) + { + TPixel[] source = CreatePixelTestData(count); + Vector4[] expected = CreateExpectedVector4Data(source); + + TestOperation( + source, + expected, + (s, d) => Operations.ToVector4(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToScaledVector4(int count) + { + TPixel[] source = CreateScaledPixelTestData(count); + Vector4[] expected = CreateExpectedScaledVector4Data(source); + + TestOperation( + source, + expected, + (s, d) => Operations.ToScaledVector4(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromRgb24Bytes(int count) + { + byte[] source = CreateByteTestData(count * 3); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i3 = i * 3; + + expected[i].PackFromRgba32(new Rgba32(source[i3 + 0], source[i3 + 1], source[i3 + 2], 255)); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromRgb24Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToRgb24Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 3]; + var rgb = default(Rgb24); + + for (int i = 0; i < count; i++) + { + int i3 = i * 3; + rgb.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i3] = rgb.R; + expected[i3 + 1] = rgb.G; + expected[i3 + 2] = rgb.B; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToRgb24Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromRgba32Bytes(int count) + { + byte[] source = CreateByteTestData(count * 4); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + + expected[i].PackFromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromRgba32Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToRgba32Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 4]; + var rgba = default(Rgba32); + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + rgba.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i4] = rgba.R; + expected[i4 + 1] = rgba.G; + expected[i4 + 2] = rgba.B; + expected[i4 + 3] = rgba.A; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToRgba32Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromRgb48Bytes(int count) + { + byte[] source = CreateByteTestData(count * 6); + Span sourceSpan = source.AsSpan(); + var expected = new TPixel[count]; + + var rgba64 = new Rgba64(0, 0, 0, 65535); + for (int i = 0; i < count; i++) + { + int i6 = i * 6; + rgba64.Rgb = MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]; + expected[i].PackFromRgba64(rgba64); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromRgb48Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToRgb48Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 6]; + Rgb48 rgb = default; + + for (int i = 0; i < count; i++) + { + int i6 = i * 6; + rgb.PackFromScaledVector4(source[i].ToScaledVector4()); + Rgba64Bytes rgb48Bytes = Unsafe.As(ref rgb); + expected[i6] = rgb48Bytes[0]; + expected[i6 + 1] = rgb48Bytes[1]; + expected[i6 + 2] = rgb48Bytes[2]; + expected[i6 + 3] = rgb48Bytes[3]; + expected[i6 + 4] = rgb48Bytes[4]; + expected[i6 + 5] = rgb48Bytes[5]; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToRgb48Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromRgba64Bytes(int count) + { + byte[] source = CreateByteTestData(count * 8); + Span sourceSpan = source.AsSpan(); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i8 = i * 8; + expected[i].PackFromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromRgba64Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToRgba64Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 8]; + Rgba64 rgba = default; + + for (int i = 0; i < count; i++) + { + int i8 = i * 8; + rgba.PackFromScaledVector4(source[i].ToScaledVector4()); + Rgba64Bytes rgba64Bytes = Unsafe.As(ref rgba); + expected[i8] = rgba64Bytes[0]; + expected[i8 + 1] = rgba64Bytes[1]; + expected[i8 + 2] = rgba64Bytes[2]; + expected[i8 + 3] = rgba64Bytes[3]; + expected[i8 + 4] = rgba64Bytes[4]; + expected[i8 + 5] = rgba64Bytes[5]; + expected[i8 + 6] = rgba64Bytes[6]; + expected[i8 + 7] = rgba64Bytes[7]; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToRgba64Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromBgr24Bytes(int count) + { + byte[] source = CreateByteTestData(count * 3); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i3 = i * 3; + + expected[i].PackFromRgba32(new Rgba32(source[i3 + 2], source[i3 + 1], source[i3 + 0], 255)); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromBgr24Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToBgr24Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 3]; + var bgr = default(Bgr24); + + for (int i = 0; i < count; i++) + { + int i3 = i * 3; + bgr.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i3] = bgr.B; + expected[i3 + 1] = bgr.G; + expected[i3 + 2] = bgr.R; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToBgr24Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromBgra32Bytes(int count) + { + byte[] source = CreateByteTestData(count * 4); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + + expected[i].PackFromRgba32(new Rgba32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromBgra32Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToBgra32Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 4]; + var bgra = default(Bgra32); + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + bgra.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i4] = bgra.B; + expected[i4 + 1] = bgra.G; + expected[i4 + 2] = bgra.R; + expected[i4 + 3] = bgra.A; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToBgra32Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromArgb32Bytes(int count) + { + byte[] source = CreateByteTestData(count * 4); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + + expected[i].PackFromRgba32(new Rgba32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromArgb32Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToArgb32Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 4]; + var argb = default(Argb32); + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + argb.PackFromScaledVector4(source[i].ToScaledVector4()); + + expected[i4] = argb.A; + expected[i4 + 1] = argb.R; + expected[i4 + 2] = argb.G; + expected[i4 + 3] = argb.B; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToArgb32Bytes(s, d.GetSpan(), count) + ); + } + + private class TestBuffers : IDisposable + where TSource : struct + where TDest : struct + { + public TSource[] SourceBuffer { get; } + public IMemoryOwner ActualDestBuffer { get; } + public TDest[] ExpectedDestBuffer { get; } + + public TestBuffers(TSource[] source, TDest[] expectedDest) + { + this.SourceBuffer = source; + this.ExpectedDestBuffer = expectedDest; + this.ActualDestBuffer = Configuration.Default.MemoryAllocator.Allocate(expectedDest.Length); + } + + public void Dispose() => this.ActualDestBuffer.Dispose(); + + private const float Tolerance = 0.0001f; + + public void Verify() + { + int count = this.ExpectedDestBuffer.Length; + + if (typeof(TDest) == typeof(Vector4)) + { + + Span expected = MemoryMarshal.Cast(this.ExpectedDestBuffer.AsSpan()); + Span actual = MemoryMarshal.Cast(this.ActualDestBuffer.GetSpan()); + + for (int i = 0; i < count; i++) + { + // ReSharper disable PossibleNullReferenceException + Assert.Equal(expected[i], actual[i], new ApproximateFloatComparer(0.001f)); + // ReSharper restore PossibleNullReferenceException + } + } + else + { + Span expected = this.ExpectedDestBuffer.AsSpan(); + Span actual = this.ActualDestBuffer.GetSpan(); + for (int i = 0; i < count; i++) + { + Assert.Equal(expected[i], actual[i]); + } + } + } + } + + internal static void TestOperation( + TSource[] source, + TDest[] expected, + Action> action) + where TSource : struct + where TDest : struct + { + using (var buffers = new TestBuffers(source, expected)) + { + action(buffers.SourceBuffer, buffers.ActualDestBuffer); + buffers.Verify(); + } + } + + internal static Vector4[] CreateVector4TestData(int length) + { + var result = new Vector4[length]; + var rnd = new Random(42); // Deterministic random values + + for (int i = 0; i < result.Length; i++) + { + result[i] = GetVector(rnd); + } + return result; + } + + internal static TPixel[] CreatePixelTestData(int length) + { + var result = new TPixel[length]; + + var rnd = new Random(42); // Deterministic random values + + for (int i = 0; i < result.Length; i++) + { + Vector4 v = GetVector(rnd); + result[i].PackFromVector4(v); + } + + return result; + } + + internal static TPixel[] CreateScaledPixelTestData(int length) + { + var result = new TPixel[length]; + + var rnd = new Random(42); // Deterministic random values + + for (int i = 0; i < result.Length; i++) + { + Vector4 v = GetVector(rnd); + result[i].PackFromScaledVector4(v); + } + + return result; + } + + internal static byte[] CreateByteTestData(int length) + { + byte[] result = new byte[length]; + var rnd = new Random(42); // Deterministic random values + + for (int i = 0; i < result.Length; i++) + { + result[i] = (byte)rnd.Next(255); + } + return result; + } + + internal static Vector4 GetVector(Random rnd) + { + return new Vector4( + (float)rnd.NextDouble(), + (float)rnd.NextDouble(), + (float)rnd.NextDouble(), + (float)rnd.NextDouble() + ); + } + + [StructLayout(LayoutKind.Sequential)] + private unsafe struct Rgba64Bytes + { + public fixed byte Data[8]; + + 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/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs index 3a80c3436d..69ecc553e7 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs @@ -69,96 +69,96 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector2.One, new Rg32(Vector2.One * 1234.0f).ToVector2()); } - [Fact] - public void Rg32_ToRgb24() - { - // arrange - var rg32 = new Rg32(0.1f, -0.3f); - var actual = default(Rgb24); - var expected = new Rgb24(25, 0, 0); - - // act - rg32.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rg32_ToRgba32() - { - // arrange - var rg32 = new Rg32(0.1f, -0.3f); - var actual = default(Rgba32); - var expected = new Rgba32(25, 0, 0, 255); - - // act - rg32.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rg32_ToBgr24() - { - // arrange - var rg32 = new Rg32(0.1f, -0.3f); - var actual = default(Bgr24); - var expected = new Bgr24(25, 0, 0); - - // act - rg32.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rg32_ToArgb32() - { - // arrange - var rg32 = new Rg32(0.1f, -0.3f); - var actual = default(Argb32); - var expected = new Argb32(25, 0, 0, 255); - - // act - rg32.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rg32_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Rg32); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rg32_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Rg32); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void Rg32_ToRgb24() + //{ + // // arrange + // var rg32 = new Rg32(0.1f, -0.3f); + // var actual = default(Rgb24); + // var expected = new Rgb24(25, 0, 0); + + // // act + // rg32.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rg32_ToRgba32() + //{ + // // arrange + // var rg32 = new Rg32(0.1f, -0.3f); + // var actual = default(Rgba32); + // var expected = new Rgba32(25, 0, 0, 255); + + // // act + // rg32.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rg32_ToBgr24() + //{ + // // arrange + // var rg32 = new Rg32(0.1f, -0.3f); + // var actual = default(Bgr24); + // var expected = new Bgr24(25, 0, 0); + + // // act + // rg32.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rg32_ToArgb32() + //{ + // // arrange + // var rg32 = new Rg32(0.1f, -0.3f); + // var actual = default(Argb32); + // var expected = new Argb32(25, 0, 0, 255); + + // // act + // rg32.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rg32_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(Rg32); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 65535, 0); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rg32_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(Rg32); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 65535, 0, 65535); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs index d056bf30d2..fcbef1374f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -1,175 +1,175 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.PixelFormats -{ - public class Rgb24Tests - { - public static readonly TheoryData ColorData = - new TheoryData() { { 1, 2, 3 }, { 4, 5, 6 }, { 0, 255, 42 } }; - - [Theory] - [MemberData(nameof(ColorData))] - public void Constructor(byte r, byte g, byte b) - { - var p = new Rgb24(r, g, b); - - Assert.Equal(r, p.R); - Assert.Equal(g, p.G); - Assert.Equal(b, p.B); - } - - [Fact] - public unsafe void ByteLayoutIsSequentialRgb() - { - var color = new Rgb24(1, 2, 3); - byte* ptr = (byte*)&color; - - Assert.Equal(1, ptr[0]); - Assert.Equal(2, ptr[1]); - Assert.Equal(3, ptr[2]); - } - - [Theory] - [MemberData(nameof(ColorData))] - public void Equals_WhenTrue(byte r, byte g, byte b) - { - var x = new Rgb24(r, g, b); - var y = new Rgb24(r, g, b); - - Assert.True(x.Equals(y)); - Assert.True(x.Equals((object)y)); - Assert.Equal(x.GetHashCode(), y.GetHashCode()); - } - - [Theory] - [InlineData(1, 2, 3, 1, 2, 4)] - [InlineData(0, 255, 0, 0, 244, 0)] - [InlineData(1, 255, 0, 0, 255, 0)] - public void Equals_WhenFalse(byte r1, byte g1, byte b1, byte r2, byte g2, byte b2) - { - var a = new Rgb24(r1, g1, b1); - var b = new Rgb24(r2, g2, b2); - - Assert.False(a.Equals(b)); - Assert.False(a.Equals((object)b)); - } - - [Fact] - public void PackFromRgba32() - { - var rgb = default(Rgb24); - rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); - - Assert.Equal(1, rgb.R); - Assert.Equal(2, rgb.G); - Assert.Equal(3, rgb.B); - } - - private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new Vector4( - r / 255f, - g / 255f, - b / 255f, - a / 255f); - - [Fact] - public void PackFromVector4() - { - var rgb = default(Rgb24); - rgb.PackFromVector4(Vec(1, 2, 3, 4)); - - Assert.Equal(1, rgb.R); - Assert.Equal(2, rgb.G); - Assert.Equal(3, rgb.B); - } - - [Fact] - public void ToVector4() - { - var rgb = new Rgb24(1, 2, 3); - - Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); - } - - [Fact] - public void ToRgb24() - { - var rgb = new Rgb24(1, 2, 3); - var dest = default(Rgb24); - - rgb.ToRgb24(ref dest); - - Assert.Equal(rgb, dest); - } - - [Fact] - public void ToRgba32() - { - var rgb = new Rgb24(1, 2, 3); - var rgba = default(Rgba32); - - rgb.ToRgba32(ref rgba); - - Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); - } - - [Fact] - public void ToBgr24() - { - var rgb = new Rgb24(1, 2, 3); - var bgr = default(Bgr24); - - rgb.ToBgr24(ref bgr); - - Assert.Equal(new Bgr24(1, 2, 3), bgr); - } - - [Fact] - public void ToBgra32() - { - var rgb = new Rgb24(1, 2, 3); - var bgra = default(Bgra32); - - rgb.ToBgra32(ref bgra); - - Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); - } - - [Fact] - public void Rgb24_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Rgb24); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb24_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Rgb24); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } - } -} \ No newline at end of file +//// Copyright (c) Six Labors and contributors. +//// Licensed under the Apache License, Version 2.0. + +//using System; +//using System.Numerics; +//using SixLabors.ImageSharp.PixelFormats; +//using Xunit; + +//namespace SixLabors.ImageSharp.Tests.PixelFormats +//{ +// public class Rgb24Tests +// { +// public static readonly TheoryData ColorData = +// new TheoryData() { { 1, 2, 3 }, { 4, 5, 6 }, { 0, 255, 42 } }; + +// [Theory] +// [MemberData(nameof(ColorData))] +// public void Constructor(byte r, byte g, byte b) +// { +// var p = new Rgb24(r, g, b); + +// Assert.Equal(r, p.R); +// Assert.Equal(g, p.G); +// Assert.Equal(b, p.B); +// } + +// [Fact] +// public unsafe void ByteLayoutIsSequentialRgb() +// { +// var color = new Rgb24(1, 2, 3); +// byte* ptr = (byte*)&color; + +// Assert.Equal(1, ptr[0]); +// Assert.Equal(2, ptr[1]); +// Assert.Equal(3, ptr[2]); +// } + +// [Theory] +// [MemberData(nameof(ColorData))] +// public void Equals_WhenTrue(byte r, byte g, byte b) +// { +// var x = new Rgb24(r, g, b); +// var y = new Rgb24(r, g, b); + +// Assert.True(x.Equals(y)); +// Assert.True(x.Equals((object)y)); +// Assert.Equal(x.GetHashCode(), y.GetHashCode()); +// } + +// [Theory] +// [InlineData(1, 2, 3, 1, 2, 4)] +// [InlineData(0, 255, 0, 0, 244, 0)] +// [InlineData(1, 255, 0, 0, 255, 0)] +// public void Equals_WhenFalse(byte r1, byte g1, byte b1, byte r2, byte g2, byte b2) +// { +// var a = new Rgb24(r1, g1, b1); +// var b = new Rgb24(r2, g2, b2); + +// Assert.False(a.Equals(b)); +// Assert.False(a.Equals((object)b)); +// } + +// [Fact] +// public void PackFromRgba32() +// { +// var rgb = default(Rgb24); +// rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); + +// Assert.Equal(1, rgb.R); +// Assert.Equal(2, rgb.G); +// Assert.Equal(3, rgb.B); +// } + +// private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new Vector4( +// r / 255f, +// g / 255f, +// b / 255f, +// a / 255f); + +// [Fact] +// public void PackFromVector4() +// { +// var rgb = default(Rgb24); +// rgb.PackFromVector4(Vec(1, 2, 3, 4)); + +// Assert.Equal(1, rgb.R); +// Assert.Equal(2, rgb.G); +// Assert.Equal(3, rgb.B); +// } + +// [Fact] +// public void ToVector4() +// { +// var rgb = new Rgb24(1, 2, 3); + +// Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); +// } + +// [Fact] +// public void ToRgb24() +// { +// var rgb = new Rgb24(1, 2, 3); +// var dest = default(Rgb24); + +// rgb.ToRgb24(ref dest); + +// Assert.Equal(rgb, dest); +// } + +// [Fact] +// public void ToRgba32() +// { +// var rgb = new Rgb24(1, 2, 3); +// var rgba = default(Rgba32); + +// rgb.ToRgba32(ref rgba); + +// Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); +// } + +// [Fact] +// public void ToBgr24() +// { +// var rgb = new Rgb24(1, 2, 3); +// var bgr = default(Bgr24); + +// rgb.ToBgr24(ref bgr); + +// Assert.Equal(new Bgr24(1, 2, 3), bgr); +// } + +// [Fact] +// public void ToBgra32() +// { +// var rgb = new Rgb24(1, 2, 3); +// var bgra = default(Bgra32); + +// rgb.ToBgra32(ref bgra); + +// Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); +// } + +// [Fact] +// public void Rgb24_PackFromRgb48_ToRgb48() +// { +// // arrange +// var input = default(Rgb24); +// var actual = default(Rgb48); +// var expected = new Rgb48(65535, 0, 65535); + +// // act +// input.PackFromRgb48(expected); +// input.ToRgb48(ref actual); + +// // assert +// Assert.Equal(expected, actual); +// } + +// [Fact] +// public void Rgb24_PackFromRgba64_ToRgba64() +// { +// // arrange +// var input = default(Rgb24); +// var actual = default(Rgba64); +// var expected = new Rgba64(65535, 0, 65535, 65535); + +// // act +// input.PackFromRgba64(expected); +// input.ToRgba64(ref actual); + +// // assert +// Assert.Equal(expected, actual); +// } +// } +//} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index 77d6544f00..2af488e3cd 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -1,199 +1,192 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.PixelFormats -{ - public class Rgb48Tests - { - [Fact] - public void Rgb48_Values() - { - var rgb = new Rgba64(5243, 9830, 19660, 29491); - - Assert.Equal(5243, rgb.R); - Assert.Equal(9830, rgb.G); - Assert.Equal(19660, rgb.B); - Assert.Equal(29491, rgb.A); - - rgb = new Rgba64(5243 / 65535F, 9830 / 65535F, 19660 / 65535F, 29491 / 65535F); - - Assert.Equal(5243, rgb.R); - Assert.Equal(9830, rgb.G); - Assert.Equal(19660, rgb.B); - Assert.Equal(29491, rgb.A); - } - - [Fact] - public void Rgb48_ToVector4() - { - Assert.Equal(new Vector4(0, 0, 0, 1), new Rgb48(Vector3.Zero).ToVector4()); - Assert.Equal(Vector4.One, new Rgb48(Vector3.One).ToVector4()); - } - - [Fact] - public void Rgb48_ToScaledVector4() - { - // arrange - var short2 = new Rgb48(Vector3.One); - - // act - Vector4 actual = short2.ToScaledVector4(); - - // assert - Assert.Equal(1, actual.X); - Assert.Equal(1, actual.Y); - Assert.Equal(1, actual.Z); - Assert.Equal(1, actual.W); - } - - [Fact] - public void Rgb48_PackFromScaledVector4() - { - // arrange - var pixel = default(Rgb48); - var short3 = new Rgb48(Vector3.One); - var expected = new Rgb48(Vector3.One); - - // act - Vector4 scaled = short3.ToScaledVector4(); - pixel.PackFromScaledVector4(scaled); - - // assert - Assert.Equal(expected, pixel); - } - - [Fact] - public void Rgb48_Clamping() - { - Assert.Equal(new Vector4(0, 0, 0, 1), new Rgb48(Vector3.One * -1234.0f).ToVector4()); - Assert.Equal(Vector4.One, new Rgb48(Vector3.One * 1234.0f).ToVector4()); - } - - [Fact] - public void Rgb48_ToRgb24() - { - // arrange - var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); - var actual = default(Rgb24); - var expected = new Rgb24(20, 38, 76); - - // act - rgba48.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_ToRgba32() - { - // arrange - var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); - var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 76, 255); - - // act - rgba48.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_ToArgb32() - { - // arrange - var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); - var actual = default(Argb32); - var expected = new Argb32(20, 38, 76, 255); - - // act - rgba48.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_ToBgr24() - { - // arrange - var rgb48 = new Rgb48(0.08f, 0.15f, 0.30f); - var actual = default(Bgr24); - var expected = new Bgr24(20, 38, 76); - - // act - rgb48.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_ToBgra32() - { - // arrange - var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); - var actual = default(Bgra32); - var expected = new Bgra32(20, 38, 76, 255); - - // act - rgba48.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_PackFromRgba32_ToRgba32() - { - // arrange - var rgb48 = default(Rgb48); - var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 76, 255); - - // act - rgb48.PackFromRgba32(expected); - rgb48.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Rgb48); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Rgb48); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } - } -} +//// Copyright (c) Six Labors and contributors. +//// Licensed under the Apache License, Version 2.0. + +//using System.Numerics; +//using SixLabors.ImageSharp.PixelFormats; +//using Xunit; + +//namespace SixLabors.ImageSharp.Tests.PixelFormats +//{ +// public class Rgb48Tests +// { +// [Fact] +// public void Rgb48_Values() +// { +// var rgb = new Rgba64(5243, 9830, 19660, 29491); + +// Assert.Equal(5243, rgb.R); +// Assert.Equal(9830, rgb.G); +// Assert.Equal(19660, rgb.B); +// Assert.Equal(29491, rgb.A); +// } + +// [Fact] +// public void Rgb48_ToVector4() +// { +// Assert.Equal(new Vector4(0, 0, 0, 1), new Rgb48(0, 0, 0, 0).ToVector4()); +// Assert.Equal(Vector4.One, new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue).ToVector4()); +// } + +// [Fact] +// public void Rgb48_ToScaledVector4() +// { +// // arrange +// var short2 = new Rgb48(Vector3.One); + +// // act +// Vector4 actual = short2.ToScaledVector4(); + +// // assert +// Assert.Equal(1, actual.X); +// Assert.Equal(1, actual.Y); +// Assert.Equal(1, actual.Z); +// Assert.Equal(1, actual.W); +// } + +// [Fact] +// public void Rgb48_PackFromScaledVector4() +// { +// // arrange +// var pixel = default(Rgb48); +// var short3 = new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); +// var expected = new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); + +// // act +// Vector4 scaled = short3.ToScaledVector4(); +// pixel.PackFromScaledVector4(scaled); + +// // assert +// Assert.Equal(expected, pixel); +// } + +// //[Fact] +// //public void Rgb48_Clamping() +// //{ +// // Assert.Equal(new Vector4(0, 0, 0, 1), new Rgb48(Vector3.One * -1234.0f).ToVector4()); +// // Assert.Equal(Vector4.One, new Rgb48(Vector3.One * 1234.0f).ToVector4()); +// //} + +// //[Fact] +// //public void Rgb48_ToRgb24() +// //{ +// // // arrange +// // var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); +// // var actual = default(Rgb24); +// // var expected = new Rgb24(20, 38, 76); + +// // // act +// // rgba48.ToRgb24(ref actual); + +// // // assert +// // Assert.Equal(expected, actual); +// //} + +// //[Fact] +// //public void Rgb48_ToRgba32() +// //{ +// // // arrange +// // var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); +// // var actual = default(Rgba32); +// // var expected = new Rgba32(20, 38, 76, 255); + +// // // act +// // rgba48.ToRgba32(ref actual); + +// // // assert +// // Assert.Equal(expected, actual); +// //} + +// //[Fact] +// //public void Rgb48_ToArgb32() +// //{ +// // // arrange +// // var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); +// // var actual = default(Argb32); +// // var expected = new Argb32(20, 38, 76, 255); + +// // // act +// // rgba48.ToArgb32(ref actual); + +// // // assert +// // Assert.Equal(expected, actual); +// //} + +// //[Fact] +// //public void Rgba64_ToBgr24() +// //{ +// // // arrange +// // var rgb48 = new Rgb48(0.08f, 0.15f, 0.30f); +// // var actual = default(Bgr24); +// // var expected = new Bgr24(20, 38, 76); + +// // // act +// // rgb48.ToBgr24(ref actual); + +// // // assert +// // Assert.Equal(expected, actual); +// //} + +// //[Fact] +// //public void Rgb48_ToBgra32() +// //{ +// // // arrange +// // var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); +// // var actual = default(Bgra32); +// // var expected = new Bgra32(20, 38, 76, 255); + +// // // act +// // rgba48.ToBgra32(ref actual); + +// // // assert +// // Assert.Equal(expected, actual); +// //} + +// //[Fact] +// //public void Rgb48_PackFromRgba32_ToRgba32() +// //{ +// // // arrange +// // var rgb48 = default(Rgb48); +// // var actual = default(Rgba32); +// // var expected = new Rgba32(20, 38, 76, 255); + +// // // act +// // rgb48.PackFromRgba32(expected); +// // rgb48.ToRgba32(ref actual); + +// // // assert +// // Assert.Equal(expected, actual); +// //} + +// //[Fact] +// //public void Rgb48_PackFromRgb48_ToRgb48() +// //{ +// // // arrange +// // var input = default(Rgb48); +// // var actual = default(Rgb48); +// // var expected = new Rgb48(65535, 0, 65535); + +// // // act +// // input.PackFromRgb48(expected); +// // input.ToRgb48(ref actual); + +// // // assert +// // Assert.Equal(expected, actual); +// //} + +// //[Fact] +// //public void Rgb48_PackFromRgba64_ToRgba64() +// //{ +// // // arrange +// // var input = default(Rgb48); +// // var actual = default(Rgba64); +// // var expected = new Rgba64(65535, 0, 65535, 65535); + +// // // act +// // input.PackFromRgba64(expected); +// // input.ToRgba64(ref actual); + +// // // assert +// // Assert.Equal(expected, actual); +// //} +// } +//} diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs index fcb3b6c7c8..d8ad6d3f1e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs @@ -71,144 +71,144 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One, new Rgba1010102(Vector4.One * 1234.0f).ToVector4()); } - [Fact] - public void Rgba1010102_ToRgb24() - { - // arrange - var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(25, 0, 128); - - // act - rgba.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_ToRgba32() - { - // arrange - var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(25, 0, 128, 0); - - // act - rgba.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_ToBgr24() - { - // arrange - var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(25, 0, 128); - - // act - rgba.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_ToBgra32() - { - // arrange - var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(25, 0, 128, 0); - - // act - rgba.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_PackFromRgba32_ToRgba32() - { - // arrange - var rgba = default(Rgba1010102); - var expected = new Rgba32(25, 0, 128, 0); - var actual = default(Rgba32); - - // act - rgba.PackFromRgba32(expected); - rgba.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_PackFromBgra32_ToBgra32() - { - // arrange - var rgba = default(Rgba1010102); - var expected = new Bgra32(25, 0, 128, 0); - var actual = default(Bgra32); - - // act - rgba.PackFromBgra32(expected); - rgba.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_PackFromArgb32_ToArgb32() - { - // arrange - var rgba = default(Rgba1010102); - var expected = new Argb32(25, 0, 128, 0); - var actual = default(Argb32); - - // act - rgba.PackFromArgb32(expected); - rgba.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Rgba1010102); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Rgba1010102); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void Rgba1010102_ToRgb24() + //{ + // // arrange + // var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Rgb24); + // var expected = new Rgb24(25, 0, 128); + + // // act + // rgba.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rgba1010102_ToRgba32() + //{ + // // arrange + // var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Rgba32); + // var expected = new Rgba32(25, 0, 128, 0); + + // // act + // rgba.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rgba1010102_ToBgr24() + //{ + // // arrange + // var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Bgr24); + // var expected = new Bgr24(25, 0, 128); + + // // act + // rgba.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rgba1010102_ToBgra32() + //{ + // // arrange + // var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Bgra32); + // var expected = new Bgra32(25, 0, 128, 0); + + // // act + // rgba.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rgba1010102_PackFromRgba32_ToRgba32() + //{ + // // arrange + // var rgba = default(Rgba1010102); + // var expected = new Rgba32(25, 0, 128, 0); + // var actual = default(Rgba32); + + // // act + // rgba.PackFromRgba32(expected); + // rgba.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rgba1010102_PackFromBgra32_ToBgra32() + //{ + // // arrange + // var rgba = default(Rgba1010102); + // var expected = new Bgra32(25, 0, 128, 0); + // var actual = default(Bgra32); + + // // act + // rgba.PackFromBgra32(expected); + // rgba.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rgba1010102_PackFromArgb32_ToArgb32() + //{ + // // arrange + // var rgba = default(Rgba1010102); + // var expected = new Argb32(25, 0, 128, 0); + // var actual = default(Argb32); + + // // act + // rgba.PackFromArgb32(expected); + // rgba.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rgba1010102_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(Rgba1010102); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 0, 65535); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rgba1010102_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(Rgba1010102); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 0, 65535, 65535); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs index 4b2c187765..30a5f961b7 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs @@ -19,12 +19,12 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void AreEqual() { - Rgba32 color1 = new Rgba32(0, 0, 0); - Rgba32 color2 = new Rgba32(0, 0, 0, 1F); - Rgba32 color3 = Rgba32.FromHex("#000"); - Rgba32 color4 = Rgba32.FromHex("#000F"); - Rgba32 color5 = Rgba32.FromHex("#000000"); - Rgba32 color6 = Rgba32.FromHex("#000000FF"); + var color1 = new Rgba32(0, 0, 0); + var color2 = new Rgba32(0, 0, 0, 1F); + var color3 = Rgba32.FromHex("#000"); + var color4 = Rgba32.FromHex("#000F"); + var color5 = Rgba32.FromHex("#000000"); + var color6 = Rgba32.FromHex("#000000FF"); Assert.Equal(color1, color2); Assert.Equal(color1, color3); @@ -39,11 +39,11 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void AreNotEqual() { - Rgba32 color1 = new Rgba32(255, 0, 0, 255); - Rgba32 color2 = new Rgba32(0, 0, 0, 255); - Rgba32 color3 = Rgba32.FromHex("#000"); - Rgba32 color4 = Rgba32.FromHex("#000000"); - Rgba32 color5 = Rgba32.FromHex("#FF000000"); + var color1 = new Rgba32(255, 0, 0, 255); + var color2 = new Rgba32(0, 0, 0, 255); + var color3 = Rgba32.FromHex("#000"); + var color4 = Rgba32.FromHex("#000000"); + var color5 = Rgba32.FromHex("#FF000000"); Assert.NotEqual(color1, color2); Assert.NotEqual(color1, color3); @@ -57,25 +57,25 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void ConstructorAssignsProperties() { - Rgba32 color1 = new Rgba32(1, .1f, .133f, .864f); + var color1 = new Rgba32(1, .1f, .133f, .864f); Assert.Equal(255, color1.R); Assert.Equal((byte)Math.Round(.1f * 255), color1.G); Assert.Equal((byte)Math.Round(.133f * 255), color1.B); Assert.Equal((byte)Math.Round(.864f * 255), color1.A); - Rgba32 color2 = new Rgba32(1, .1f, .133f); + var color2 = new Rgba32(1, .1f, .133f); Assert.Equal(255, color2.R); Assert.Equal(Math.Round(.1f * 255), color2.G); Assert.Equal(Math.Round(.133f * 255), color2.B); Assert.Equal(255, color2.A); - Rgba32 color4 = new Rgba32(new Vector3(1, .1f, .133f)); + var color4 = new Rgba32(new Vector3(1, .1f, .133f)); Assert.Equal(255, color4.R); Assert.Equal(Math.Round(.1f * 255), color4.G); Assert.Equal(Math.Round(.133f * 255), color4.B); Assert.Equal(255, color4.A); - Rgba32 color5 = new Rgba32(new Vector4(1, .1f, .133f, .5f)); + var color5 = new Rgba32(new Vector4(1, .1f, .133f, .5f)); Assert.Equal(255, color5.R); Assert.Equal(Math.Round(.1f * 255), color5.G); Assert.Equal(Math.Round(.133f * 255), color5.B); @@ -112,7 +112,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public unsafe void ByteLayout() { - Rgba32 color = new Rgba32(1, 2, 3, 4); + var color = new Rgba32(1, 2, 3, 4); byte* colorBase = (byte*)&color; Assert.Equal(1, colorBase[0]); Assert.Equal(2, colorBase[1]); @@ -181,23 +181,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One, new Rgba32(Vector4.One * +1234.0f).ToVector4()); } - [Fact] - public void Rgba32_ToRgb24() - { - // arrange - var rgba = new Rgba32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(0x1a, 0, 0x80); - - // act - rgba.ToRgb24(ref actual); - - // assert - Assert.Equal(expected.R, actual.R); - Assert.Equal(expected.G, actual.G); - Assert.Equal(expected.B, actual.B); - } - [Fact] public void Rgba32_ToRgba32() { @@ -207,52 +190,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(0x1a, 0, 0x80, 0); // act - rgba.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba32_ToBgr24() - { - // arrange - var rgba = new Rgba32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(0x1a, 0, 0x80); - - // act - rgba.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba32_ToBgra32() - { - // arrange - var rgba = new Rgba32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(0x1a, 0, 0x80, 0); - - // act - rgba.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba32_ToArgb32() - { - // arrange - var rgba = new Rgba32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(0x1a, 0, 0x80, 0); - - // act - rgba.ToArgb32(ref actual); + actual.PackFromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -268,7 +206,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act rgba.PackFromRgba32(expected); - rgba.ToRgba32(ref actual); + actual.PackFromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -284,7 +222,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act rgba.PackFromBgra32(expected); - rgba.ToBgra32(ref actual); + actual.PackFromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -300,14 +238,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act rgba.PackFromArgb32(expected); - rgba.ToArgb32(ref actual); + actual.PackFromRgba32(rgba); // assert Assert.Equal(expected, actual); } [Fact] - public void Rgba32_PackFromRgb48_ToRgb48() + public void Rgba32_PackFromRgb48() { // arrange var input = default(Rgba32); @@ -316,14 +254,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgb48(expected); - input.ToRgb48(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); } [Fact] - public void Rgba32_PackFromRgba64_ToRgba64() + public void Rgba32_PackFromRgba64() { // arrange var input = default(Rgba32); @@ -332,7 +270,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgba64(expected); - input.ToRgba64(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index 92b36a1c62..185fc5635d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -13,33 +13,31 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public void Rgba64_PackedValues() { Assert.Equal((ulong)0x73334CCC2666147B, new Rgba64(5243, 9830, 19660, 29491).PackedValue); - Assert.Equal((ulong)0x73334CCC2666147B, new Rgba64(0.08f, 0.15f, 0.30f, 0.45f).PackedValue); - var rgba = new Rgba64(0x73334CCC2666147B); - Assert.Equal(5243, rgba.R); - Assert.Equal(9830, rgba.G); - Assert.Equal(19660, rgba.B); - Assert.Equal(29491, rgba.A); // Test the limits. - Assert.Equal((ulong)0x0, new Rgba64(Vector4.Zero).PackedValue); - Assert.Equal(0xFFFFFFFFFFFFFFFF, new Rgba64(Vector4.One).PackedValue); + Assert.Equal((ulong)0x0, new Rgba64(0, 0, 0, 0).PackedValue); + Assert.Equal(0xFFFFFFFFFFFFFFFF, new Rgba64( + ushort.MaxValue, + ushort.MaxValue, + ushort.MaxValue, + ushort.MaxValue).PackedValue); + // Test data ordering - Assert.Equal(0xC7AD8F5C570A1EB8, new Rgba64(((float)0x1EB8) / 0xffff, ((float)0x570A) / 0xffff, ((float)0x8F5C) / 0xffff, ((float)0xC7AD) / 0xffff).PackedValue); - Assert.Equal(0xC7AD8F5C570A1EB8, new Rgba64(0.12f, 0.34f, 0.56f, 0.78f).PackedValue); + Assert.Equal(0xC7AD8F5C570A1EB8, new Rgba64(0x1EB8, 0x570A, 0x8F5C, 0xC7AD).PackedValue); } [Fact] public void Rgba64_ToVector4() { - Assert.Equal(Vector4.Zero, new Rgba64(Vector4.Zero).ToVector4()); - Assert.Equal(Vector4.One, new Rgba64(Vector4.One).ToVector4()); + Assert.Equal(Vector4.Zero, new Rgba64(0, 0, 0, 0).ToVector4()); + Assert.Equal(Vector4.One, new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue).ToVector4()); } [Fact] public void Rgba64_ToScaledVector4() { // arrange - var short2 = new Rgba64(Vector4.One); + var short2 = new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); // act Vector4 actual = short2.ToScaledVector4(); @@ -56,7 +54,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { // arrange var pixel = default(Rgba64); - var short4 = new Rgba64(Vector4.One); + var short4 = new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); const ulong expected = 0xFFFFFFFFFFFFFFFF; // act @@ -71,131 +69,78 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void Rgba64_Clamping() { - Assert.Equal(Vector4.Zero, new Rgba64(Vector4.One * -1234.0f).ToVector4()); - Assert.Equal(Vector4.One, new Rgba64(Vector4.One * 1234.0f).ToVector4()); - } - - [Fact] - public void Rgba64_ToRgb24() - { - // arrange - var rgba64 = new Rgba64(0.08f, 0.15f, 0.30f, 0.45f); - var actual = default(Rgb24); - var expected = new Rgb24(20, 38, 76); - - // act - rgba64.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_ToRgba32() - { - // arrange - var rgba64 = new Rgba64(0.08f, 0.15f, 0.30f, 0.45f); - var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 76, 115); - - // act - rgba64.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_ToArgb32() - { - // arrange - var rgba64 = new Rgba64(0.08f, 0.15f, 0.30f, 0.45f); - var actual = default(Argb32); - var expected = new Argb32(20, 38, 76, 115); - - // act - rgba64.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_ToBgr24() - { - // arrange - var rgba64 = new Rgba64(0.08f, 0.15f, 0.30f, 0.45f); - var actual = default(Bgr24); - var expected = new Bgr24(20, 38, 76); - - // act - rgba64.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_ToBgra32() - { - // arrange - var rgba64 = new Rgba64(0.08f, 0.15f, 0.30f, 0.45f); - var actual = default(Bgra32); - var expected = new Bgra32(20, 38, 76, 115); - - // act - rgba64.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_PackFromRgba32_ToRgba32() - { - // arrange - var rgba64 = default(Rgba64); - var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 76, 115); - - // act - rgba64.PackFromRgba32(expected); - rgba64.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Rgba64); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); + var zero = default(Rgba64); + var one = default(Rgba64); + zero.PackFromVector4(Vector4.One * -1234.0f); + one.PackFromVector4(Vector4.One * 1234.0f); + Assert.Equal(Vector4.Zero, zero.ToVector4()); + Assert.Equal(Vector4.One, one.ToVector4()); } - [Fact] - public void Rgba64_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Rgba64); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void Rgba64_ToRgba32() + //{ + // // arrange + // var rgba64 = new Rgba64( + // (ushort)(0.08f * ushort.MaxValue), + // (ushort)(0.15f * ushort.MaxValue), + // (ushort)(0.30f * ushort.MaxValue), + // (ushort)(0.45f * ushort.MaxValue)); + // var actual = default(Rgba32); + // var expected = new Rgba32(20, 38, 76, 115); + + // // act + // actual = rgba64.ToRgba32(); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rgba64_PackFromRgba32_ToRgba32() + //{ + // // arrange + // var rgba64 = default(Rgba64); + // var actual = default(Rgba32); + // var expected = new Rgba32(20, 38, 76, 115); + + // // act + // rgba64.PackFromRgba32(expected); + // actual = rgba64.ToRgba32(); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rgb48_PackFromRgb48() + //{ + // // arrange + // var input = default(Rgba64); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 0, 65535); + + // // act + // input.PackFromRgb48(expected); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rgba64_PackFromRgba64() + //{ + // // arrange + // var input = default(Rgba64); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 0, 65535, 0); + + // // act + // input.PackFromRgba64(expected); + // actual.PackFromScaledVector4(input.ToScaledVector4()); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs index a21b647a74..9b5fceac77 100644 --- a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs @@ -19,12 +19,12 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void AreEqual() { - RgbaVector color1 = new RgbaVector(0, 0, 0F); - RgbaVector color2 = new RgbaVector(0, 0, 0, 1F); - RgbaVector color3 = RgbaVector.FromHex("#000"); - RgbaVector color4 = RgbaVector.FromHex("#000F"); - RgbaVector color5 = RgbaVector.FromHex("#000000"); - RgbaVector color6 = RgbaVector.FromHex("#000000FF"); + var color1 = new RgbaVector(0, 0, 0F); + var color2 = new RgbaVector(0, 0, 0, 1F); + var color3 = RgbaVector.FromHex("#000"); + var color4 = RgbaVector.FromHex("#000F"); + var color5 = RgbaVector.FromHex("#000000"); + var color6 = RgbaVector.FromHex("#000000FF"); Assert.Equal(color1, color2); Assert.Equal(color1, color3); @@ -39,11 +39,11 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void AreNotEqual() { - RgbaVector color1 = new RgbaVector(1, 0, 0, 1); - RgbaVector color2 = new RgbaVector(0, 0, 0, 1); - RgbaVector color3 = RgbaVector.FromHex("#000"); - RgbaVector color4 = RgbaVector.FromHex("#000000"); - RgbaVector color5 = RgbaVector.FromHex("#FF000000"); + var color1 = new RgbaVector(1, 0, 0, 1); + var color2 = new RgbaVector(0, 0, 0, 1); + var color3 = RgbaVector.FromHex("#000"); + var color4 = RgbaVector.FromHex("#000000"); + var color5 = RgbaVector.FromHex("#FF000000"); Assert.NotEqual(color1, color2); Assert.NotEqual(color1, color3); @@ -57,29 +57,17 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void ConstructorAssignsProperties() { - RgbaVector color1 = new RgbaVector(1, .1F, .133F, .864F); + var color1 = new RgbaVector(1, .1F, .133F, .864F); Assert.Equal(1F, color1.R); Assert.Equal(.1F, color1.G); Assert.Equal(.133F, color1.B); Assert.Equal(.864F, color1.A); - RgbaVector color2 = new RgbaVector(1, .1f, .133f); + var color2 = new RgbaVector(1, .1f, .133f); Assert.Equal(1F, color2.R); Assert.Equal(.1F, color2.G); Assert.Equal(.133F, color2.B); Assert.Equal(1F, color2.A); - - RgbaVector color4 = new RgbaVector(new Vector3(1, .1f, .133f)); - Assert.Equal(1F, color4.R); - Assert.Equal(.1F, color4.G); - Assert.Equal(.133F, color4.B); - Assert.Equal(1F, color4.A); - - RgbaVector color5 = new RgbaVector(new Vector4(1, .1f, .133f, .5f)); - Assert.Equal(1F, color5.R); - Assert.Equal(.1F, color5.G); - Assert.Equal(.133F, color5.B); - Assert.Equal(.5F, color5.A); } /// @@ -88,7 +76,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void FromAndToHex() { - RgbaVector color = RgbaVector.FromHex("#AABBCCDD"); + var color = RgbaVector.FromHex("#AABBCCDD"); Assert.Equal(170 / 255F, color.R); Assert.Equal(187 / 255F, color.G); Assert.Equal(204 / 255F, color.B); @@ -116,7 +104,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void FloatLayout() { - RgbaVector color = new RgbaVector(1F, 2, 3, 4); + var color = new RgbaVector(1F, 2, 3, 4); Vector4 colorBase = Unsafe.As(ref Unsafe.Add(ref color, 0)); float[] ordered = new float[4]; colorBase.CopyTo(ordered); @@ -128,7 +116,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void RgbaVector_PackFromRgb48_ToRgb48() + public void RgbaVector_PackFromRgb48() { // arrange var input = default(RgbaVector); @@ -137,14 +125,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgb48(expected); - input.ToRgb48(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); } [Fact] - public void RgbaVector_PackFromRgba64_ToRgba64() + public void RgbaVector_PackFromRgba64() { // arrange var input = default(RgbaVector); @@ -153,7 +141,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgba64(expected); - input.ToRgba64(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs index 5c75fcbbbc..5f2f45b3be 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // arrange var pixel = default(Short2); var short2 = new Short2(Vector2.One * 0x7FFF); - ulong expected = 0x7FFF7FFF; + const ulong expected = 0x7FFF7FFF; // act Vector4 scaled = short2.ToScaledVector4(); @@ -79,21 +79,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } - [Fact] - public void Short2_ToRgb24() - { - // arrange - var short2 = new Short2(127.5f, -5.3f); - var actual = default(Rgb24); - var expected = new Rgb24(128, 127, 0); - - // act - short2.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - [Fact] public void Short2_ToRgba32() { @@ -103,52 +88,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(128, 127, 0, 255); // act - short2.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short2_ToBgr24() - { - // arrange - var short2 = new Short2(127.5f, -5.3f); - var actual = default(Bgr24); - var expected = new Bgr24(128, 127, 0); - - // act - short2.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short2_ToArgb32() - { - // arrange - var short2 = new Short2(127.5f, -5.3f); - var actual = default(Argb32); - var expected = new Argb32(128, 127, 0, 255); - - // act - short2.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short2_ToBgra32() - { - // arrange - var short2 = new Short2(127.5f, -5.3f); - var actual = default(Bgra32); - var expected = new Bgra32(128, 127, 0, 255); - - // act - short2.ToBgra32(ref actual); + actual = short2.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -164,14 +104,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short2.PackFromRgba32(expected); - short2.ToRgba32(ref actual); + actual = short2.ToRgba32(); // assert Assert.Equal(expected, actual); } [Fact] - public void Short2_PackFromRgb48_ToRgb48() + public void Short2_PackFromRgb48() { // arrange var input = default(Short2); @@ -180,14 +120,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgb48(expected); - input.ToRgb48(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); } [Fact] - public void Short2_PackFromRgba64_ToRgba64() + public void Short2_PackFromRgba64() { // arrange var input = default(Short2); @@ -196,7 +136,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgba64(expected); - input.ToRgba64(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs index 59dc385d4d..4245fcf381 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // arrange var short4 = new Short4(Vector4.One * 0x7FFF); Vector4 scaled = short4.ToScaledVector4(); - long expected = 0x7FFF7FFF7FFF7FFF; + const long expected = 0x7FFF7FFF7FFF7FFF; // act var pixel = default(Short4); @@ -83,36 +83,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One * -0x8000, vector2); } - [Fact] - public void Short4_ToRgb24() - { - // arrange - var shortValue = new Short4(11547, 12653, 29623, 193); - var actual = default(Rgb24); - var expected = new Rgb24(172, 177, 243); - - // act - shortValue.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short4_ToBgr24() - { - // arrange - var shortValue = new Short4(11547, 12653, 29623, 193); - var actual = default(Bgr24); - var expected = new Bgr24(172, 177, 243); - - // act - shortValue.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - [Fact] public void Short4_ToRgba32() { @@ -122,37 +92,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(172, 177, 243, 128); // act - shortValue.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short4_ToBgra32() - { - // arrange - var shortValue = new Short4(11547, 12653, 29623, 193); - var actual = default(Bgra32); - var expected = new Bgra32(172, 177, 243, 128); - - // act - shortValue.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short4_ToArgb32() - { - // arrange - var shortValue = new Short4(11547, 12653, 29623, 193); - var actual = default(Argb32); - var expected = new Argb32(172, 177, 243, 128); - - // act - shortValue.ToArgb32(ref actual); + actual = shortValue.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -168,7 +108,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short4.PackFromRgba32(expected); - short4.ToRgba32(ref actual); + actual = short4.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -184,7 +124,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short4.PackFromBgra32(expected); - short4.ToBgra32(ref actual); + actual.PackFromRgba32(short4.ToRgba32()); // assert Assert.Equal(expected, actual); @@ -200,7 +140,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short4.PackFromArgb32(expected); - short4.ToArgb32(ref actual); + actual.PackFromRgba32(short4.ToRgba32()); // assert Assert.Equal(expected, actual); @@ -216,7 +156,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgb48(expected); - input.ToRgb48(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -232,7 +172,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgba64(expected); - input.ToRgba64(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs index 1fca398fcd..29c97ce35f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Tests.Colors public void Color_Types_From_Bytes_Produce_Equal_Scaled_Component_OutPut() { var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Tests.Colors public void Color_Types_From_Vector4_Produce_Equal_Scaled_Component_OutPut() { var color = new Rgba32(new Vector4(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F)); - var colorVector = new RgbaVector(new Vector4(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F)); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.Tests.Colors public void Color_Types_From_Vector3_Produce_Equal_Scaled_Component_OutPut() { var color = new Rgba32(new Vector3(24 / 255F, 48 / 255F, 96 / 255F)); - var colorVector = new RgbaVector(new Vector3(24 / 255F, 48 / 255F, 96 / 255F)); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); @@ -73,76 +73,28 @@ namespace SixLabors.ImageSharp.Tests.Colors public void Color_Types_To_Vector4_Produce_Equal_OutPut() { var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); Assert.Equal(color.ToVector4(), colorVector.ToVector4()); } - [Fact] - public void Color_Types_To_RgbBytes_Produce_Equal_OutPut() - { - var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); - - var rgb = default(Rgb24); - var rgbVector = default(Rgb24); - - color.ToRgb24(ref rgb); - colorVector.ToRgb24(ref rgbVector); - - Assert.Equal(rgb, rgbVector); - } - [Fact] public void Color_Types_To_RgbaBytes_Produce_Equal_OutPut() { var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); - - var rgba = default(Rgba32); - var rgbaVector = default(Rgba32); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); - color.ToRgba32(ref rgba); - colorVector.ToRgba32(ref rgbaVector); + var rgba = color.ToRgba32(); + var rgbaVector = colorVector.ToRgba32(); Assert.Equal(rgba, rgbaVector); } - [Fact] - public void Color_Types_To_BgrBytes_Produce_Equal_OutPut() - { - var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); - - var bgr = default(Bgr24); - var bgrVector = default(Bgr24); - - color.ToBgr24(ref bgr); - colorVector.ToBgr24(ref bgrVector); - - Assert.Equal(bgr, bgrVector); - } - - [Fact] - public void Color_Types_To_BgraBytes_Produce_Equal_OutPut() - { - var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); - - var bgra = default(Bgra32); - var bgraVector = default(Bgra32); - - color.ToBgra32(ref bgra); - colorVector.ToBgra32(ref bgraVector); - - Assert.Equal(bgra, bgraVector); - } - [Fact] public void Color_Types_To_Hex_Produce_Equal_OutPut() { var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); // 183060C0 Assert.Equal(color.ToHex(), colorVector.ToHex()); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index edc6994e7a..17240839db 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -65,10 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms nameof(KnownResamplers.Lanczos8), }; - public AffineTransformTests(ITestOutputHelper output) - { - this.Output = output; - } + public AffineTransformTests(ITestOutputHelper output) => this.Output = output; /// /// The output of an "all white" image should be "all white" or transparent, regardless of the transformation and the resampler. @@ -240,12 +237,14 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms where TPixel : struct, IPixel { Span data = image.Frames.RootFrame.GetPixelSpan(); - var rgba = default(Rgba32); var white = new Rgb24(255, 255, 255); foreach (TPixel pixel in data) { - pixel.ToRgba32(ref rgba); - if (rgba.A == 0) continue; + var rgba = pixel.ToRgba32(); + if (rgba.A == 0) + { + continue; + } Assert.Equal(white, rgba.Rgb); } diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index c2b1c26c54..719e9793a0 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -97,12 +97,11 @@ namespace SixLabors.ImageSharp.Tests { // Transparent pixels are much more likely to be found at the end of a palette int index = -1; - var trans = default(Rgba32); for (int i = quantized.Palette.Length - 1; i >= 0; i--) { - quantized.Palette[i].ToRgba32(ref trans); + var trans = quantized.Palette[i].ToRgba32(); - if (trans.Equals(default(Rgba32))) + if (trans.Equals(default)) { index = i; } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index 65b32e0880..70b630adf1 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -72,7 +72,10 @@ namespace SixLabors.ImageSharp.Tests extension = '.' + extension; } - if (fn != string.Empty) fn = '_' + fn; + if (fn != string.Empty) + { + fn = '_' + fn; + } string pixName = ""; @@ -274,17 +277,14 @@ namespace SixLabors.ImageSharp.Tests } public static void ModifyPixel(Image img, int x, int y, byte perChannelChange) - where TPixel : struct, IPixel - { - ModifyPixel(img.Frames.RootFrame, x, y, perChannelChange); - } + where TPixel : struct, IPixel => ModifyPixel(img.Frames.RootFrame, x, y, perChannelChange); public static void ModifyPixel(ImageFrame img, int x, int y, byte perChannelChange) where TPixel : struct, IPixel { TPixel pixel = img[x, y]; Rgba64 rgbaPixel = default; - pixel.ToRgba64(ref rgbaPixel); + rgbaPixel.PackFromScaledVector4(pixel.ToScaledVector4()); ushort change = (ushort)Math.Round((perChannelChange / 255F) * 65535F); if (rgbaPixel.R + perChannelChange <= 255) diff --git a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs index 5a14f2e26e..e6a5ffc84b 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs @@ -80,10 +80,10 @@ namespace SixLabors.ImageSharp.Tests } else { - ca.ToRgb24(ref rgb1); - cb.ToRgb24(ref rgb2); + rgb1 = ca.ToRgba32().Rgb; + rgb2 = cb.ToRgba32().Rgb; - if (rgb1.R != rgb2.R || rgb1.G != rgb2.G || rgb1.B != rgb2.B) + if (!rgb1.Equals(rgb2)) { return false; } @@ -94,10 +94,7 @@ namespace SixLabors.ImageSharp.Tests return true; } - public static string ToCsv(this IEnumerable items, string separator = ",") - { - return String.Join(separator, items.Select(o => String.Format(CultureInfo.InvariantCulture, "{0}", o))); - } + public static string ToCsv(this IEnumerable items, string separator = ",") => string.Join(separator, items.Select(o => string.Format(CultureInfo.InvariantCulture, "{0}", o))); public static Type GetClrType(this PixelTypes pixelType) => PixelTypes2ClrTypes[pixelType]; @@ -141,10 +138,7 @@ namespace SixLabors.ImageSharp.Tests internal static PixelTypes[] GetAllPixelTypes() => (PixelTypes[])Enum.GetValues(typeof(PixelTypes)); internal static TPixel GetPixelOfNamedColor(string colorName) - where TPixel : struct, IPixel - { - return (TPixel)typeof(NamedColors).GetTypeInfo().GetField(colorName).GetValue(null); - } + where TPixel : struct, IPixel => (TPixel)typeof(NamedColors).GetTypeInfo().GetField(colorName).GetValue(null); /// /// Utility for testing image processor extension methods: diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs index 5305eb2ba3..1d284af15e 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs @@ -2,36 +2,26 @@ // Licensed under the Apache License, Version 2.0. using System; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; -using Xunit.Abstractions; - using System.Collections.Concurrent; using System.IO; - using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; +using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests { - using SixLabors.Memory; - public class TestImageProviderTests { - public TestImageProviderTests(ITestOutputHelper output) - { - this.Output = output; - } + public TestImageProviderTests(ITestOutputHelper output) => this.Output = output; private ITestOutputHelper Output { get; } [Theory] [WithBlankImages(1, 1, PixelTypes.Rgba32)] public void NoOutputSubfolderIsPresentByDefault(TestImageProvider provider) - where TPixel : struct, IPixel - { - Assert.Empty(provider.Utility.OutputSubfolderName); - } + where TPixel : struct, IPixel => Assert.Empty(provider.Utility.OutputSubfolderName); [Theory] [WithBlankImages(42, 666, PixelTypes.Rgba32 | PixelTypes.Argb32 | PixelTypes.HalfSingle, "hello")] @@ -64,10 +54,7 @@ namespace SixLabors.ImageSharp.Tests [WithBlankImages(1, 1, PixelTypes.Alpha8, PixelTypes.Alpha8)] [WithBlankImages(1, 1, PixelTypes.Argb32, PixelTypes.Argb32)] public void PixelType_PropertyValueIsCorrect(TestImageProvider provider, PixelTypes expected) - where TPixel : struct, IPixel - { - Assert.Equal(expected, provider.PixelType); - } + where TPixel : struct, IPixel => Assert.Equal(expected, provider.PixelType); [Theory] [WithFile(TestImages.Bmp.Car, PixelTypes.All, 88)] @@ -96,7 +83,7 @@ namespace SixLabors.ImageSharp.Tests // Couldn't make xUnit happy without this hackery: - private static ConcurrentDictionary invocationCounts = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary invocationCounts = new ConcurrentDictionary(); private string callerName = null; @@ -160,7 +147,7 @@ namespace SixLabors.ImageSharp.Tests return new Image(42, 42); } - private static ConcurrentDictionary invocationCounts = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary invocationCounts = new ConcurrentDictionary(); private string callerName = null; @@ -287,14 +274,12 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(10, img.Width); Assert.Equal(20, img.Height); - var rgba = default(Rgba32); - Buffer2D pixels = img.GetRootFramePixelBuffer(); for (int y = 0; y < pixels.Height; y++) { for (int x = 0; x < pixels.Width; x++) { - pixels[x, y].ToRgba32(ref rgba); + var rgba = pixels[x, y].ToRgba32(); Assert.Equal(255, rgba.R); Assert.Equal(100, rgba.G); @@ -311,10 +296,7 @@ namespace SixLabors.ImageSharp.Tests /// /// public static Image CreateTestImage() - where TPixel : struct, IPixel - { - return new Image(3, 3); - } + where TPixel : struct, IPixel => new Image(3, 3); [Theory] [WithMemberFactory(nameof(CreateTestImage), PixelTypes.All)] From d4327c51290f1809e32a202b47c5f8f490d16375 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 10 Oct 2018 08:58:22 +0100 Subject: [PATCH 134/381] Fix linear gradient brush test. --- .../Drawing/FillLinearGradientBrushTests.cs | 37 ++++++++++--------- tests/Images/External | 2 +- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs index 3522ade7c4..74a61dfbaa 100644 --- a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs @@ -283,10 +283,12 @@ namespace SixLabors.ImageSharp.Tests.Drawing { // it's diagonal, so for any (a, a) on the gradient line, for all (a-x, b+x) - +/- depending on the diagonal direction - must be the same color) TPixel colorOnDiagonal = image[i, i]; + + // TODO: This is incorrect. from -0 to < 0 ?? int orthoCount = 0; for (int offset = -orthoCount; offset < orthoCount; offset++) { - Assert.Equal(colorOnDiagonal, image[i + horizontalSign * offset, i + verticalSign * offset]); + Assert.Equal(colorOnDiagonal, image[i + (horizontalSign * offset), i + (verticalSign * offset)]); } } @@ -302,8 +304,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing [Theory] [WithBlankImages(500, 500, PixelTypes.Rgba32, 0, 0, 499, 499, new[] { 0f, .2f, .5f, .9f }, new[] { 0, 0, 1, 1 })] [WithBlankImages(500, 500, PixelTypes.Rgba32, 0, 499, 499, 0, new[] { 0f, 0.2f, 0.5f, 0.9f }, new[] { 0, 1, 2, 3 })] - [WithBlankImages(500, 500, PixelTypes.Rgba32, 499, 499, 0, 0, new[] { 0f, 0.7f, 0.8f, 0.9f}, new[] { 0, 1, 2, 0 })] - [WithBlankImages(500, 500, PixelTypes.Rgba32, 0, 0, 499, 499, new[] { 0f, .5f, 1f}, new[]{0, 1, 3})] + [WithBlankImages(500, 500, PixelTypes.Rgba32, 499, 499, 0, 0, new[] { 0f, 0.7f, 0.8f, 0.9f }, new[] { 0, 1, 2, 0 })] + [WithBlankImages(500, 500, PixelTypes.Rgba32, 0, 0, 499, 499, new[] { 0f, .5f, 1f }, new[] { 0, 1, 3 })] public void ArbitraryGradients( TestImageProvider provider, int startX, int startY, @@ -312,35 +314,36 @@ namespace SixLabors.ImageSharp.Tests.Drawing int[] stopColorCodes) where TPixel : struct, IPixel { - TPixel[] colors = { - NamedColors.Navy, NamedColors.LightGreen, NamedColors.Yellow, - NamedColors.Red - }; + TPixel[] colors = + { + NamedColors.Navy, NamedColors.LightGreen, NamedColors.Yellow, + NamedColors.Red + }; var coloringVariant = new StringBuilder(); - ColorStop[] colorStops = new ColorStop[stopPositions.Length]; + var colorStops = new ColorStop[stopPositions.Length]; for (int i = 0; i < stopPositions.Length; i++) { TPixel color = colors[stopColorCodes[i % colors.Length]]; float position = stopPositions[i]; colorStops[i] = new ColorStop(position, color); - coloringVariant.AppendFormat(CultureInfo.InvariantCulture, "{0}@{1};", color, position); + coloringVariant.AppendFormat(CultureInfo.InvariantCulture, "{0}@{1};", color.ToRgba32().ToHex(), position); } FormattableString variant = $"({startX},{startY})_TO_({endX},{endY})__[{coloringVariant}]"; provider.VerifyOperation( image => - { - var unicolorLinearGradientBrush = new LinearGradientBrush( - new SixLabors.Primitives.Point(startX, startY), - new SixLabors.Primitives.Point(endX, endY), - GradientRepetitionMode.None, - colorStops); + { + var unicolorLinearGradientBrush = new LinearGradientBrush( + new SixLabors.Primitives.Point(startX, startY), + new SixLabors.Primitives.Point(endX, endY), + GradientRepetitionMode.None, + colorStops); - image.Mutate(x => x.Fill(unicolorLinearGradientBrush)); - }, + image.Mutate(x => x.Fill(unicolorLinearGradientBrush)); + }, variant, false, false); diff --git a/tests/Images/External b/tests/Images/External index 03c7fa7582..1a807d17b4 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 03c7fa7582dea75cea0d49514ccb7e1b6dc9e780 +Subproject commit 1a807d17b4cf5ab50558983d4137614cabe96ce3 From dc2792b5503baef3fc2ad5dea61b91f6af15482e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 10 Oct 2018 13:06:47 +0100 Subject: [PATCH 135/381] 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 b82ea9884871c300e78820d874c795a6a4867cca Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 10 Oct 2018 13:19:16 +0100 Subject: [PATCH 136/381] 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 d520b57e21d700417a1a01af8dd776fc1db703f8 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 11 Oct 2018 10:36:02 +0100 Subject: [PATCH 137/381] 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 d673d1126dda6bab847469fe1ffc776ac954f067 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 12 Oct 2018 12:36:55 +0100 Subject: [PATCH 138/381] 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 2919fe9c2c1bf5c6f2ddc147017faa5392d88863 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 12 Oct 2018 13:19:51 +0100 Subject: [PATCH 139/381] 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 d5836c1a0f8f39bba22d9fc566115a6cfb38ef48 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 12 Oct 2018 13:58:51 +0100 Subject: [PATCH 140/381] 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 58d06c23f8e70b23325449ee5a3c56a44808738f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 12 Oct 2018 22:21:23 +0100 Subject: [PATCH 141/381] 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 c349c2b248e6740d23bf3e82af4c7d99c2d8cf31 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 13 Oct 2018 16:55:17 +0100 Subject: [PATCH 142/381] Fix up Gray8 and Gary16 tests --- .../PixelFormats/Gray16Tests.cs | 296 +++++++----------- .../PixelFormats/Gray8Tests.cs | 248 +++++---------- 2 files changed, 189 insertions(+), 355 deletions(-) diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs index 166fb230ac..db4fa70197 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs @@ -15,197 +15,115 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [InlineData(32767)] [InlineData(42)] public void Gray16_PackedValue_EqualsInput(ushort input) + => Assert.Equal(input, new Gray16(input).PackedValue); + + [Fact] + public void Gray16_PackFromScaledVector4() + { + // Arrange + Gray16 gray = default; + const ushort expected = 32767; + Vector4 scaled = new Gray16(expected).ToScaledVector4(); + + // Act + gray.PackFromScaledVector4(scaled); + ushort actual = gray.PackedValue; + + // Assert + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(0)] + [InlineData(65535)] + [InlineData(32767)] + public void Gray16_ToScaledVector4(ushort input) + { + // Arrange + var gray = new Gray16(input); + + // Act + Vector4 actual = gray.ToScaledVector4(); + + // Assert + float vectorInput = input / 65535F; + Assert.Equal(vectorInput, actual.X); + Assert.Equal(vectorInput, actual.Y); + Assert.Equal(vectorInput, actual.Z); + Assert.Equal(1F, actual.W); + } + + [Fact] + public void Gray16_PackFromVector4() + { + // Arrange + Gray16 gray = default; + const ushort expected = 32767; + var vector = new Gray16(expected).ToVector4(); + + // Act + gray.PackFromVector4(vector); + ushort actual = gray.PackedValue; + + // Assert + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(0)] + [InlineData(65535)] + [InlineData(32767)] + public void Gray16_ToVector4(ushort input) { - Assert.Equal(input, new Gray16(input).PackedValue); + // Arrange + var gray = new Gray16(input); + + // Act + var actual = gray.ToVector4(); + + // Assert + float vectorInput = input / 65535F; + Assert.Equal(vectorInput, actual.X); + Assert.Equal(vectorInput, actual.Y); + Assert.Equal(vectorInput, actual.Z); + Assert.Equal(1F, actual.W); } - //[Theory] - //[InlineData(0)] - //[InlineData(65535)] - //[InlineData(32767)] - //public void Gray16_ToVector4(ushort input) - //{ - // // arrange - // var gray = new Gray16(input); - - // // act - // var actual = gray.ToVector4(); - - // // assert - // Assert.Equal(input, actual.X); - // Assert.Equal(input, actual.Y); - // Assert.Equal(input, actual.Z); - // Assert.Equal(1, actual.W); - //} - - //[Theory] - //[InlineData(0)] - //[InlineData(65535)] - //[InlineData(32767)] - //public void Gray16_ToScaledVector4(ushort input) - //{ - // // arrange - // var gray = new Gray16(input); - - // // act - // var actual = gray.ToScaledVector4(); - - // // assert - // float scaledInput = input / 65535f; - // Assert.Equal(scaledInput, actual.X); - // Assert.Equal(scaledInput, actual.Y); - // Assert.Equal(scaledInput, actual.Z); - // Assert.Equal(1, actual.W); - //} - - //[Fact] - //public void Gray16_PackFromScaledVector4() - //{ - // // arrange - // Gray16 gray = default; - // int expected = 32767; - // Vector4 scaled = new Gray16((ushort)expected).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // ushort actual = gray.PackedValue; - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray16_PackFromScaledVector4_ToRgb24() - //{ - // // arrange - // Rgb24 actual = default; - // Gray16 gray = default; - // var expected = new Rgb24(128, 128, 128); - // Vector4 scaled = new Gray16(32768).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray16_PackFromScaledVector4_ToRgba32() - //{ - // // arrange - // Rgba32 actual = default; - // Gray16 gray = default; - // var expected = new Rgba32(128, 128, 128, 255); - // Vector4 scaled = new Gray16(32768).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray16_PackFromScaledVector4_ToBgr24() - //{ - // // arrange - // Bgr24 actual = default; - // Gray16 gray = default; - // var expected = new Bgr24(128, 128, 128); - // Vector4 scaled = new Gray16(32768).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray16_PackFromScaledVector4_ToBgra32() - //{ - // // arrange - // Bgra32 actual = default; - // Gray16 gray = default; - // var expected = new Bgra32(128,128,128); - // Vector4 scaled = new Gray16(32768).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray16_PackFromScaledVector4_ToArgb32() - //{ - // // arrange - // Gray16 gray = default; - // Argb32 actual = default; - // var expected = new Argb32(128, 128, 128); - // Vector4 scaled = new Gray16(32768).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray16_PackFromScaledVector4_ToRgba64() - //{ - // // arrange - // Gray16 gray = default; - // Rgba64 actual = default; - // var expected = new Rgba64(65535, 65535, 65535, 65535); - // Vector4 scaled = new Gray16(65535).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray16_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var gray = default(Gray16); - // var actual = default(Rgb48); - // var expected = new Rgb48(0, 0, 0); - - // // act - // gray.PackFromRgb48(expected); - // gray.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray16_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var gray = default(Gray16); - // var actual = default(Rgba64); - // var expected = new Rgba64(0, 0, 0, 65535); - - // // act - // gray.PackFromRgba64(expected); - // gray.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} + [Fact] + public void Gray16_PackFromRgba32() + { + // Arrange + Gray16 gray = default; + const byte rgb = 128; + ushort scaledRgb = ImageMaths.UpscaleFrom8BitTo16Bit(rgb); + ushort expected = ImageMaths.Get16BitBT709Luminance(scaledRgb, scaledRgb, scaledRgb); + + // Act + gray.PackFromRgba32(new Rgba32(rgb, rgb, rgb)); + ushort actual = gray.PackedValue; + + // Assert + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(0)] + [InlineData(65535)] + [InlineData(8100)] + public void Gray16_ToRgba32(ushort input) + { + // Arrange + ushort expected = ImageMaths.DownScaleFrom16BitTo8Bit(input); + var gray = new Gray16(input); + + // Act + var actual = gray.ToRgba32(); + + // Assert + Assert.Equal(expected, actual.R); + Assert.Equal(expected, actual.G); + Assert.Equal(expected, actual.B); + Assert.Equal(byte.MaxValue, actual.A); + } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs index ae114a0e26..aaca6c8776 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs @@ -15,28 +15,23 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [InlineData(10)] [InlineData(42)] public void Gray8_PackedValue_EqualsInput(byte input) + => Assert.Equal(input, new Gray8(input).PackedValue); + + [Fact] + public void Gray8_PackFromScaledVector4() { - Assert.Equal(input, new Gray8(input).PackedValue); - } + // Arrange + Gray8 gray = default; + const byte expected = 128; + Vector4 scaled = new Gray8(expected).ToScaledVector4(); - //[Theory] - //[InlineData(0, 0)] - //[InlineData(255, 1)] - //[InlineData(30)] - //public void Gray8_ToVector4(byte input) - //{ - // // arrange - // var gray = new Gray8(input); - - // // act - // var actual = gray.ToVector4(); - - // // assert - // Assert.Equal(input, actual.X); - // Assert.Equal(input, actual.Y); - // Assert.Equal(input, actual.Z); - // Assert.Equal(1, actual.W); - //} + // Act + gray.PackFromScaledVector4(scaled); + byte actual = gray.PackedValue; + + // Assert + Assert.Equal(expected, actual); + } [Theory] [InlineData(0)] @@ -44,14 +39,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [InlineData(30)] public void Gray8_ToScaledVector4(byte input) { - // arrange + // Arrange var gray = new Gray8(input); - // act - var actual = gray.ToScaledVector4(); + // Act + Vector4 actual = gray.ToScaledVector4(); - // assert - float scaledInput = input / 255f; + // Assert + float scaledInput = input / 255F; Assert.Equal(scaledInput, actual.X); Assert.Equal(scaledInput, actual.Y); Assert.Equal(scaledInput, actual.Z); @@ -59,153 +54,74 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Gray8_PackFromScaledVector4() + public void Gray8_PackFromVector4() { - // arrange + // Arrange Gray8 gray = default; - int expected = 128; - Vector4 scaled = new Gray8(128).ToScaledVector4(); + const int expected = 128; + var vector = new Gray8(expected).ToVector4(); - // act - gray.PackFromScaledVector4(scaled); + // Act + gray.PackFromVector4(vector); + byte actual = gray.PackedValue; + + // Assert + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(0)] + [InlineData(255)] + [InlineData(30)] + public void Gray8_ToVector4(byte input) + { + // Arrange + var gray = new Gray8(input); + + // Act + var actual = gray.ToVector4(); + + // Assert + float scaledInput = input / 255F; + Assert.Equal(scaledInput, actual.X); + Assert.Equal(scaledInput, actual.Y); + Assert.Equal(scaledInput, actual.Z); + Assert.Equal(1, actual.W); + } + + [Fact] + public void Gray8_PackFromRgba32() + { + // Arrange + Gray8 gray = default; + const byte rgb = 128; + byte expected = ImageMaths.Get8BitBT709Luminance(rgb, rgb, rgb); + + // Act + gray.PackFromRgba32(new Rgba32(rgb, rgb, rgb)); byte actual = gray.PackedValue; - // assert + // Assert Assert.Equal(expected, actual); } - //[Fact] - //public void Gray8_PackFromScaledVector4_ToRgb24() - //{ - // // arrange - // Rgb24 actual = default; - // Gray8 gray = default; - // var expected = new Rgb24(128, 128, 128); - // Vector4 scaled = new Gray8(128).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray8_PackFromScaledVector4_ToRgba32() - //{ - // // arrange - // Rgba32 actual = default; - // Gray8 gray = default; - // var expected = new Rgba32(128, 128, 128, 255); - // Vector4 scaled = new Gray8(128).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray8_PackFromScaledVector4_ToBgr24() - //{ - // // arrange - // Bgr24 actual = default; - // Gray8 gray = default; - // var expected = new Bgr24(128, 128, 128); - // Vector4 scaled = new Gray8(128).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray8_PackFromScaledVector4_ToBgra32() - //{ - // // arrange - // Bgra32 actual = default; - // Gray8 gray = default; - // var expected = new Bgra32(128,128,128); - // Vector4 scaled = new Gray8(128).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray8_PackFromScaledVector4_ToArgb32() - //{ - // // arrange - // Gray8 gray = default; - // Argb32 actual = default; - // var expected = new Argb32(128, 128, 128); - // Vector4 scaled = new Gray8(128).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray8_PackFromScaledVector4_ToRgba64() - //{ - // // arrange - // Gray8 gray = default; - // Rgba64 actual = default; - // var expected = new Rgba64(65535, 65535, 65535, 65535); - // Vector4 scaled = new Gray8(255).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray8_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var gray = default(Gray8); - // var actual = default(Rgb48); - // var expected = new Rgb48(0, 0, 0); - - // // act - // gray.PackFromRgb48(expected); - // gray.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray8_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var gray = default(Gray8); - // var actual = default(Rgba64); - // var expected = new Rgba64(0, 0, 0, 65535); - - // // act - // gray.PackFromRgba64(expected); - // gray.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} + [Theory] + [InlineData(0)] + [InlineData(255)] + [InlineData(30)] + public void Gray8_ToRgba32(byte input) + { + // Arrange + var gray = new Gray8(input); + + // Act + var actual = gray.ToRgba32(); + + // Assert + Assert.Equal(input, actual.R); + Assert.Equal(input, actual.G); + Assert.Equal(input, actual.B); + Assert.Equal(byte.MaxValue, actual.A); + } } -} +} \ No newline at end of file From 1f7df77c5c72acae8fc5ca32d5604ece8a26fb24 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 13 Oct 2018 17:36:12 +0100 Subject: [PATCH 143/381] Fix up pixel format tests --- .../PixelFormats/Argb32Tests.cs | 155 ---------- .../PixelFormats/Bgr24Tests.cs | 76 ----- .../PixelFormats/Bgr565Tests.cs | 107 ------- .../PixelFormats/Bgra32Tests.cs | 76 ----- .../PixelFormats/Bgra4444Tests.cs | 155 ---------- .../PixelFormats/Bgra5551Tests.cs | 155 ---------- .../PixelFormats/Byte4Tests.cs | 155 ---------- .../PixelFormats/HalfSingleTests.cs | 107 ------- .../PixelFormats/HalfVector2Tests.cs | 107 ------- .../PixelFormats/HalfVector4Tests.cs | 155 ---------- .../PixelFormats/NormalizedByte2Tests.cs | 123 -------- .../PixelFormats/NormalizedByte4Tests.cs | 140 --------- .../PixelFormats/NormalizedShort2Tests.cs | 124 -------- .../PixelFormats/NormalizedShort4Tests.cs | 142 +-------- .../PixelFormats/Rg32Tests.cs | 92 ------ .../PixelFormats/Rgb24Tests.cs | 287 +++++++----------- .../PixelFormats/Rgb48Tests.cs | 253 ++++----------- .../PixelFormats/Rgba1010102Tests.cs | 148 +-------- .../PixelFormats/Rgba64Tests.cs | 75 +---- tests/Images/External | 2 +- 20 files changed, 198 insertions(+), 2436 deletions(-) diff --git a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs index 53545f517a..6186793c5b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs @@ -66,160 +66,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.Zero, new Argb32(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One, new Argb32(Vector4.One * +1234.0f).ToVector4()); } - - //[Fact] - //public void Argb32_ToRgb24() - //{ - // // arrange - // var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - // var actual = default(Rgb24); - // var expected = new Rgb24(0x1a, 0, 0x80); - - // // act - // argb.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Argb32_ToRgba32() - //{ - // // arrange - // var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - // var actual = default(Rgba32); - // var expected = new Rgba32(0x1a, 0, 0x80, 0); - - // // act - // argb.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Argb32_ToBgr24() - //{ - // // arrange - // var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - // var actual = default(Bgr24); - // var expected = new Bgr24(0x1a, 0, 0x80); - - // // act - // argb.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Argb32_ToBgra32() - //{ - // // arrange - // var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - // var actual = default(Bgra32); - // var expected = new Bgra32(0x1a, 0, 0x80, 0); - - // // act - // argb.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Argb32_ToArgb32() - //{ - // // arrange - // var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - // var actual = default(Argb32); - // var expected = new Argb32(0x1a, 0, 0x80, 0); - - // // act - // argb.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Argb32_PackFromRgba32_ToRgba32() - //{ - // // arrange - // var argb = default(Argb32); - // var actual = default(Rgba32); - // var expected = new Rgba32(0x1a, 0, 0x80, 0); - - // // act - // argb.PackFromRgba32(expected); - // argb.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Argb32_PackFromBgra32_ToBgra32() - //{ - // // arrange - // var argb = default(Argb32); - // var actual = default(Bgra32); - // var expected = new Bgra32(0x1a, 0, 0x80, 0); - - // // act - // argb.PackFromBgra32(expected); - // argb.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Argb32_PackFromArgb32_ToArgb32() - //{ - // // arrange - // var argb = default(Argb32); - // var actual = default(Argb32); - // var expected = new Argb32(0x1a, 0, 0x80, 0); - - // // act - // argb.PackFromArgb32(expected); - // argb.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Argb32_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var argb = default(Argb32); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 0, 65535); - - // // act - // argb.PackFromRgb48(expected); - // argb.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Argb32_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var argb = default(Argb32); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 0, 65535, 0); - - // // act - // argb.PackFromRgba64(expected); - // argb.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs index e742789e4d..96589a03e0 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs @@ -95,81 +95,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); } - - //[Fact] - //public void ToRgb24() - //{ - // var rgb = new Bgr24(1, 2, 3); - // var dest = default(Rgb24); - - // rgb.ToRgb24(ref dest); - - // Assert.Equal(new Rgb24(1, 2, 3), dest); - //} - - //[Fact] - //public void ToRgba32() - //{ - // var rgb = new Bgr24(1, 2, 3); - // var rgba = default(Rgba32); - - // rgb.ToRgba32(ref rgba); - - // Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); - //} - - //[Fact] - //public void ToBgr24() - //{ - // var rgb = new Bgr24(1, 2, 3); - // var bgr = default(Bgr24); - - // rgb.ToBgr24(ref bgr); - - // Assert.Equal(new Bgr24(1, 2, 3), bgr); - //} - - //[Fact] - //public void ToBgra32() - //{ - // var rgb = new Bgr24(1, 2, 3); - // var bgra = default(Bgra32); - - // rgb.ToBgra32(ref bgra); - - // Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); - //} - - //[Fact] - //public void Bgr24_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(Bgr24); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 0, 65535); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgr24_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(Bgr24); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 0, 65535, 65535); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs index 6954067a34..8cbbf558d8 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs @@ -69,112 +69,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector3.Zero, new Bgr565(Vector3.One * -1234F).ToVector3()); Assert.Equal(Vector3.One, new Bgr565(Vector3.One * 1234F).ToVector3()); } - - //[Fact] - //public void Bgr565_ToRgb24() - //{ - // // arrange - // var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - // var actual = default(Rgb24); - // var expected = new Rgb24(25, 0, 132); - - // // act - // bgra.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgr565_ToRgba32() - //{ - // // arrange - // var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - // var actual = default(Rgba32); - // var expected = new Rgba32(25, 0, 132, 255); - - // // act - // bgra.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgr565_ToBgr24() - //{ - // // arrange - // var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - // var actual = default(Bgr24); - // var expected = new Bgr24(25, 0, 132); - - // // act - // bgra.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgr565_ToBgra32() - //{ - // // arrange - // var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - // var actual = default(Bgra32); - // var expected = new Bgra32(25, 0, 132, 255); - - // // act - // bgra.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgr565_ToArgb32() - //{ - // // arrange - // var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - // var actual = default(Argb32); - // var expected = new Argb32(25, 0, 132, 255); - - // // act - // bgra.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgr565_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(Bgr565); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 0, 65535); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgr565_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(Bgr565); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 0, 65535, 65535); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs index 9ff84a88c1..1b890ac494 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs @@ -102,81 +102,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vec(1, 2, 3, 4), rgb.ToVector4()); } - - //[Fact] - //public void ToRgb24() - //{ - // var c = new Bgra32(1, 2, 3, 4); - // var dest = default(Rgb24); - - // c.ToRgb24(ref dest); - - // Assert.Equal(new Rgb24(1, 2, 3), dest); - //} - - //[Fact] - //public void ToRgba32() - //{ - // var c = new Bgra32(1, 2, 3, 4); - // var rgba = default(Rgba32); - - // c.ToRgba32(ref rgba); - - // Assert.Equal(new Rgba32(1, 2, 3, 4), rgba); - //} - - //[Fact] - //public void ToBgr24() - //{ - // var rgb = new Bgra32(1, 2, 3, 4); - // var bgr = default(Bgr24); - - // rgb.ToBgr24(ref bgr); - - // Assert.Equal(new Bgr24(1, 2, 3), bgr); - //} - - //[Fact] - //public void ToBgra32() - //{ - // var rgb = new Bgra32(1, 2, 3, 4); - // var bgra = default(Bgra32); - - // rgb.ToBgra32(ref bgra); - - // Assert.Equal(new Bgra32(1, 2, 3, 4), bgra); - //} - - //[Fact] - //public void Bgra32_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(Bgra32); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 0, 65535); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra32_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(Bgra32); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 0, 65535, 0); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs index 2e6e339b6a..a2fc1a0520 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs @@ -70,160 +70,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.Zero, new Bgra4444(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One, new Bgra4444(Vector4.One * 1234.0f).ToVector4()); } - - //[Fact] - //public void Bgra4444_ToRgb24() - //{ - // // arrange - // var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Rgb24); - // var expected = new Rgb24(34, 0, 136); - - // // act - // bgra.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra4444_ToRgba32() - //{ - // // arrange - // var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Rgba32); - // var expected = new Rgba32(34, 0, 136, 0); - - // // act - // bgra.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra4444_ToBgr24() - //{ - // // arrange - // var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Bgr24); - // var expected = new Bgr24(34, 0, 136); - - // // act - // bgra.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra4444_ToBgra32() - //{ - // // arrange - // var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Bgra32); - // var expected = new Bgra32(34, 0, 136, 0); - - // // act - // bgra.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra4444_ToArgb32() - //{ - // // arrange - // var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Argb32); - // var expected = new Argb32(34, 0, 136, 0); - - // // act - // bgra.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra4444_PackFromRgba32_ToRgba32() - //{ - // // arrange - // var bgra = default(Bgra4444); - // var actual = default(Rgba32); - // var expected = new Rgba32(34, 0, 136, 0); - - // // act - // bgra.PackFromRgba32(expected); - // bgra.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra4444_PackFromBgra32_ToBgra32() - //{ - // // arrange - // var bgra = default(Bgra4444); - // var actual = default(Bgra32); - // var expected = new Bgra32(34, 0, 136, 0); - - // // act - // bgra.PackFromBgra32(expected); - // bgra.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra4444_PackFromArgb32_ToArgb32() - //{ - // // arrange - // var bgra = default(Bgra4444); - // var actual = default(Argb32); - // var expected = new Argb32(34, 0, 136, 0); - - // // act - // bgra.PackFromArgb32(expected); - // bgra.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra4444_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(Bgra4444); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 0, 65535); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra4444_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(Bgra4444); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 0, 65535, 0); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs index 3a0aec3209..084dfbd97c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs @@ -69,160 +69,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.Zero, new Bgra5551(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One, new Bgra5551(Vector4.One * 1234.0f).ToVector4()); } - - //[Fact] - //public void Bgra5551_ToRgb24() - //{ - // // arrange - // var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Rgb24); - // var expected = new Rgb24(24, 0, 131); - - // // act - // bgra.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra5551_Rgba32() - //{ - // // arrange - // var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Rgba32); - // var expected = new Rgba32(24, 0, 131, 0); - - // // act - // bgra.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra5551_ToBgr24() - //{ - // // arrange - // var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Bgr24); - // var expected = new Bgr24(24, 0, 131); - - // // act - // bgra.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra5551_Bgra32() - //{ - // // arrange - // var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Bgra32); - // var expected = new Bgra32(24, 0, 131, 0); - - // // act - // bgra.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra5551_ToArgb32() - //{ - // // arrange - // var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Argb32); - // var expected = new Argb32(24, 0, 131, 0); - - // // act - // bgra.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra5551_PackFromRgba32_ToRgba32() - //{ - // // arrange - // var bgra = default(Bgra5551); - // var expected = new Rgba32(24, 0, 131, 0); - // var actual = default(Rgba32); - - // // act - // bgra.PackFromRgba32(expected); - // bgra.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra5551_PackFromBgra32_ToBgra32() - //{ - // // arrange - // var bgra = default(Bgra5551); - // var expected = new Bgra32(24, 0, 131, 0); - // var actual = default(Bgra32); - - // // act - // bgra.PackFromBgra32(expected); - // bgra.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra5551_PackFromArgb32_ToArgb32() - //{ - // // arrange - // var bgra = default(Bgra5551); - // var expected = new Argb32(24, 0, 131, 0); - // var actual = default(Argb32); - - // // act - // bgra.PackFromArgb32(expected); - // bgra.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra5551_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(Bgra5551); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 0, 65535); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra5551_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(Bgra5551); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 0, 65535, 0); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs index d1e8cceaa4..de1c749f6c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs @@ -67,160 +67,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.Zero, new Byte4(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One * 255, new Byte4(Vector4.One * 1234.0f).ToVector4()); } - - //[Fact] - //public void Byte4_ToRgb24() - //{ - // // arrange - // var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - // var actual = default(Rgb24); - // var expected = new Rgb24(128, 0, 0); - - // // act - // byte4.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Byte4_Rgba32() - //{ - // // arrange - // var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - // var actual = default(Rgba32); - // var expected = new Rgba32(128, 0, 0, 0); - - // // act - // byte4.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Byte4_ToBgr24() - //{ - // // arrange - // var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - // var actual = default(Bgr24); - // var expected = new Bgr24(128, 0, 0); - - // // act - // byte4.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Byte4_Bgra32() - //{ - // // arrange - // var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - // var actual = default(Bgra32); - // var expected = new Bgra32(128, 0, 0, 0); - - // // act - // byte4.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Byte4_Argb32() - //{ - // // arrange - // var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - // var actual = default(Argb32); - // var expected = new Argb32(128, 0, 0, 0); - - // // act - // byte4.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Byte4_PackFromRgba32_ToRgba32() - //{ - // // arrange - // var byte4 = default(Byte4); - // var actual = default(Rgba32); - // var expected = new Rgba32(20, 38, 0, 255); - - // // act - // byte4.PackFromRgba32(expected); - // byte4.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Byte4_PackFromBgra32_ToBgra32() - //{ - // // arrange - // var byte4 = default(Byte4); - // var actual = default(Bgra32); - // var expected = new Bgra32(20, 38, 0, 255); - - // // act - // byte4.PackFromBgra32(expected); - // byte4.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Byte4_PackFromArgb32_ToArgb32() - //{ - // // arrange - // var byte4 = default(Byte4); - // var actual = default(Argb32); - // var expected = new Argb32(20, 38, 0, 255); - - // // act - // byte4.PackFromArgb32(expected); - // byte4.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Byte4_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(Byte4); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 0, 65535); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Byte4_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(Byte4); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 0, 65535, 0); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs index 1c3905854e..fed55af6f7 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs @@ -66,112 +66,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - //[Fact] - //public void HalfSingle_ToRgb24() - //{ - // // arrange - // var halfVector = new HalfSingle(.5F); - // var actual = default(Rgb24); - // var expected = new Rgb24(128, 0, 0); - - // // act - // halfVector.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfSingle_Rgba32() - //{ - // // arrange - // var halfVector = new HalfSingle(.5F); - // var actual = default(Rgba32); - // var expected = new Rgba32(128, 0, 0, 255); - - // // act - // halfVector.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfSingle_ToBgr24() - //{ - // // arrange - // var halfVector = new HalfSingle(.5F); - // var actual = default(Bgr24); - // var expected = new Bgr24(128, 0, 0); - - // // act - // halfVector.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfSingle_Bgra32() - //{ - // // arrange - // var halfVector = new HalfSingle(.5F); - // var actual = default(Bgra32); - // var expected = new Bgra32(128, 0, 0, 255); - - // // act - // halfVector.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfSingle_Argb32() - //{ - // // arrange - // var halfVector = new HalfSingle(.5F); - // var actual = default(Argb32); - // var expected = new Argb32(128, 0, 0, 255); - - // // act - // halfVector.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfSingle_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(HalfSingle); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 0, 0); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfSingle_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(HalfSingle); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 0, 0, 65535); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs index 1ceb224e5e..c775e3a0de 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs @@ -71,112 +71,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - //[Fact] - //public void HalfVector2_ToRgb24() - //{ - // // arrange - // var halfVector = new HalfVector2(.5F, .25F); - // var actual = default(Rgb24); - // var expected = new Rgb24(128, 64, 0); - - // // act - // halfVector.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector2_Rgba32() - //{ - // // arrange - // var halfVector = new HalfVector2(.5F, .25F); - // var actual = default(Rgba32); - // var expected = new Rgba32(128, 64, 0, 255); - - // // act - // halfVector.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector2_ToBgr24() - //{ - // // arrange - // var halfVector = new HalfVector2(.5F, .25F); - // var actual = default(Bgr24); - // var expected = new Bgr24(128, 64, 0); - - // // act - // halfVector.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector2_Bgra32() - //{ - // // arrange - // var halfVector = new HalfVector2(.5F, .25F); - // var actual = default(Bgra32); - // var expected = new Bgra32(128, 64, 0, 255); - - // // act - // halfVector.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector2_Argb32() - //{ - // // arrange - // var halfVector = new HalfVector2(.5F, .25F); - // var actual = default(Argb32); - // var expected = new Argb32(128, 64, 0, 255); - - // // act - // halfVector.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector2_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(HalfVector2); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 65535, 0); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector2_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(HalfVector2); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 65535, 0, 65535); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs index 3ba5718503..540a1ed08b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs @@ -65,160 +65,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - //[Fact] - //public void HalfVector4_ToRgb24() - //{ - // // arrange - // var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - // var actual = default(Rgb24); - // var expected = new Rgb24(64, 128, 191); - - // // act - // halfVector.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector4_Rgba32() - //{ - // // arrange - // var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - // var actual = default(Rgba32); - // var expected = new Rgba32(64, 128, 191, 255); - - // // act - // halfVector.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector4_ToBgr24() - //{ - // // arrange - // var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - // var actual = default(Bgr24); - // var expected = new Bgr24(64, 128, 191); - - // // act - // halfVector.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector4_Bgra32() - //{ - // // arrange - // var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - // var actual = default(Bgra32); - // var expected = new Bgra32(64, 128, 191, 255); - - // // act - // halfVector.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector4_Argb32() - //{ - // // arrange - // var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - // var actual = default(Argb32); - // var expected = new Argb32(64, 128, 191, 255); - - // // act - // halfVector.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector4_PackFromRgba32_ToRgba32() - //{ - // // arrange - // var halVector = default(HalfVector4); - // var actual = default(Rgba32); - // var expected = new Rgba32(64, 128, 191, 255); - - // // act - // halVector.PackFromRgba32(expected); - // halVector.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector4_PackFromBgra32_ToBgra32() - //{ - // // arrange - // var halVector = default(HalfVector4); - // var actual = default(Bgra32); - // var expected = new Bgra32(64, 128, 191, 255); - - // // act - // halVector.PackFromBgra32(expected); - // halVector.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector4_PackFromArgb32_ToArgb32() - //{ - // // arrange - // var halVector = default(HalfVector4); - // var actual = default(Argb32); - // var expected = new Argb32(64, 128, 191, 255); - - // // act - // halVector.PackFromArgb32(expected); - // halVector.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector4_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(HalfVector4); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 0, 65535); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector4_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(HalfVector4); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 0, 65535, 0); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs index 3ab36853b9..98b747a94f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs @@ -66,128 +66,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - //[Fact] - //public void NormalizedByte2_PackFromRgba32() - //{ - // // arrange - // var byte2 = new NormalizedByte2(); - // var rgba = new Rgba32(141, 90, 0, 0); - // int expected = 0xda0d; - - // // act - // byte2.PackFromRgba32(rgba); - // ushort actual = byte2.PackedValue; - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte2_ToRgb24() - //{ - // // arrange - // var short4 = new NormalizedByte2(0.1f, -0.3f); - // var actual = default(Rgb24); - // var expected = new Rgb24(141, 90, 0); - - // // act - // short4.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte2_ToRgba32() - //{ - // // arrange - // var short4 = new NormalizedByte2(0.1f, -0.3f); - // var actual = default(Rgba32); - // var expected = new Rgba32(141, 90, 0, 255); - - // // act - // short4.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte2_ToBgr24() - //{ - // // arrange - // var short4 = new NormalizedByte2(0.1f, -0.3f); - // var actual = default(Bgr24); - // var expected = new Bgr24(141, 90, 0); - - // // act - // short4.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte2_ToBgra32() - //{ - // // arrange - // var short4 = new NormalizedByte2(0.1f, -0.3f); - // var actual = default(Bgra32); - // var expected = new Bgra32(141, 90, 0, 255); - - // // act - // short4.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte2_ToArgb32() - //{ - // // arrange - // var short4 = new NormalizedByte2(0.1f, -0.3f); - // var actual = default(Argb32); - // var expected = new Argb32(141, 90, 0, 255); - - // // act - // short4.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte2_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(NormalizedByte2); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 65535, 0); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte2_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(NormalizedByte2); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 65535, 0, 65535); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs index acac04853f..d9cca360b2 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs @@ -60,145 +60,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - //[Fact] - //public void NormalizedByte4_ToRgb24() - //{ - // // arrange - // var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Rgb24); - // var expected = new Rgb24(141, 90, 192); - - // // act - // short4.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte4_ToRgba32() - //{ - // // arrange - // var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Rgba32); - // var expected = new Rgba32(141, 90, 192, 39); - - // // act - // short4.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte4_ToBgr24() - //{ - // // arrange - // var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Bgr24); - // var expected = new Bgr24(141, 90, 192); - - // // act - // short4.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte4_ToArgb32() - //{ - // // arrange - // var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Argb32); - // var expected = new Argb32(141, 90, 192, 39); - - // // act - // short4.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte4_PackFromRgba32_ToRgba32() - //{ - // // arrange - // var short4 = default(NormalizedByte4); - // var actual = default(Rgba32); - // var expected = new Rgba32(9, 115, 202, 127); - - // // act - // short4.PackFromRgba32(new Rgba32(9, 115, 202, 127)); - // short4.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte4_PackFromBgra32_ToRgba32() - //{ - // // arrange - // var actual = default(Bgra32); - // var short4 = default(NormalizedByte4); - // var expected = new Bgra32(9, 115, 202, 127); - - // // act - // short4.PackFromBgra32(expected); - // short4.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte4_PackFromArgb32_ToRgba32() - //{ - // // arrange - // var short4 = default(NormalizedByte4); - // var actual = default(Argb32); - // var expected = new Argb32(9, 115, 202, 127); - - // // act - // short4.PackFromArgb32(expected); - // short4.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte4_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(NormalizedByte4); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 65535, 0); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte4_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(NormalizedByte4); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 65535, 0, 65535); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs index e02d513c2a..83eab82ac8 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs @@ -69,129 +69,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - //[Fact] - //public void NormalizedShort2_PackFromRgba32_ToRgb24() - //{ - // // arrange - // var actual = default(Rgb24); - // var short2 = new NormalizedShort2(); - // var rgba = new Rgba32(141, 90, 0, 0); - // var expected = new Rgb24(141, 90, 0); - - // // act - // short2.PackFromRgba32(rgba); - // short2.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort2_ToRgb24() - //{ - // // arrange - // var short2 = new NormalizedShort2(0.1f, -0.3f); - // var actual = default(Rgb24); - // var expected = new Rgb24(141, 90, 0); - - // // act - // short2.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort2_ToRgba32() - //{ - // // arrange - // var short2 = new NormalizedShort2(0.1f, -0.3f); - // var actual = default(Rgba32); - // var expected = new Rgba32(141, 90, 0, 255); - - // // act - // short2.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort2_ToBgr24() - //{ - // // arrange - // var short2 = new NormalizedShort2(0.1f, -0.3f); - // var actual = default(Bgr24); - // var expected = new Bgr24(141, 90, 0); - - // // act - // short2.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort2_ToBgra32() - //{ - // // arrange - // var short2 = new NormalizedShort2(0.1f, -0.3f); - // var actual = default(Bgra32); - // var expected = new Bgra32(141, 90, 0, 255); - - // // act - // short2.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort2_ToArgb32() - //{ - // // arrange - // var short2 = new NormalizedShort2(0.1f, -0.3f); - // var actual = default(Argb32); - // var expected = new Argb32(141, 90, 0, 255); - - // // act - // short2.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort2_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(NormalizedShort2); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 65535, 0); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort2_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(NormalizedShort2); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 65535, 0, 65535); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs index 25ffbb348a..40b2d05e31 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // arrange var pixel = default(NormalizedShort4); Vector4 scaled = new NormalizedShort4(Vector4.One).ToScaledVector4(); - ulong expected = (ulong)0x7FFF7FFF7FFF7FFF; + ulong expected = 0x7FFF7FFF7FFF7FFF; // act pixel.PackFromScaledVector4(scaled); @@ -61,145 +61,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - //[Fact] - //public void NormalizedShort4_ToRgb24() - //{ - // // arrange - // var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Rgb24); - // var expected = new Rgb24(141, 90, 192); - - // // act - // short4.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort4_ToRgba32() - //{ - // // arrange - // var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Rgba32); - // var expected = new Rgba32(141, 90, 192, 39); - - // // act - // short4.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort4_ToBgr24() - //{ - // // arrange - // var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Bgr24); - // var expected = new Bgr24(141, 90, 192); - - // // act - // short4.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort4_ToArgb32() - //{ - // // arrange - // var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Argb32); - // var expected = new Argb32(141, 90, 192, 39); - - // // act - // short4.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort4_PackFromRgba32_ToRgba32() - //{ - // // arrange - // var short4 = default(NormalizedShort4); - // var expected = new Rgba32(9, 115, 202, 127); - // var actual = default(Rgba32); - - // // act - // short4.PackFromRgba32(expected); - // short4.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort4_PackFromBgra32_ToRgba32() - //{ - // // arrange - // var short4 = default(NormalizedShort4); - // var actual = default(Bgra32); - // var expected = new Bgra32(9, 115, 202, 127); - - // // act - // short4.PackFromBgra32(expected); - // short4.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort4_PackFromArgb32_ToRgba32() - //{ - // // arrange - // var short4 = default(NormalizedShort4); - // var actual = default(Argb32); - // var expected = new Argb32(9, 115, 202, 127); - - // // act - // short4.PackFromArgb32(expected); - // short4.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort4_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(NormalizedShort4); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 65535, 0); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort4_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(NormalizedShort4); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 65535, 0, 65535); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs index 69ecc553e7..135843e35f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs @@ -68,97 +68,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector2.Zero, new Rg32(Vector2.One * -1234.0f).ToVector2()); Assert.Equal(Vector2.One, new Rg32(Vector2.One * 1234.0f).ToVector2()); } - - //[Fact] - //public void Rg32_ToRgb24() - //{ - // // arrange - // var rg32 = new Rg32(0.1f, -0.3f); - // var actual = default(Rgb24); - // var expected = new Rgb24(25, 0, 0); - - // // act - // rg32.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rg32_ToRgba32() - //{ - // // arrange - // var rg32 = new Rg32(0.1f, -0.3f); - // var actual = default(Rgba32); - // var expected = new Rgba32(25, 0, 0, 255); - - // // act - // rg32.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rg32_ToBgr24() - //{ - // // arrange - // var rg32 = new Rg32(0.1f, -0.3f); - // var actual = default(Bgr24); - // var expected = new Bgr24(25, 0, 0); - - // // act - // rg32.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rg32_ToArgb32() - //{ - // // arrange - // var rg32 = new Rg32(0.1f, -0.3f); - // var actual = default(Argb32); - // var expected = new Argb32(25, 0, 0, 255); - - // // act - // rg32.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rg32_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(Rg32); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 65535, 0); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rg32_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(Rg32); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 65535, 0, 65535); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs index fcbef1374f..aa6d9024cd 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -1,175 +1,112 @@ -//// Copyright (c) Six Labors and contributors. -//// Licensed under the Apache License, Version 2.0. - -//using System; -//using System.Numerics; -//using SixLabors.ImageSharp.PixelFormats; -//using Xunit; - -//namespace SixLabors.ImageSharp.Tests.PixelFormats -//{ -// public class Rgb24Tests -// { -// public static readonly TheoryData ColorData = -// new TheoryData() { { 1, 2, 3 }, { 4, 5, 6 }, { 0, 255, 42 } }; - -// [Theory] -// [MemberData(nameof(ColorData))] -// public void Constructor(byte r, byte g, byte b) -// { -// var p = new Rgb24(r, g, b); - -// Assert.Equal(r, p.R); -// Assert.Equal(g, p.G); -// Assert.Equal(b, p.B); -// } - -// [Fact] -// public unsafe void ByteLayoutIsSequentialRgb() -// { -// var color = new Rgb24(1, 2, 3); -// byte* ptr = (byte*)&color; - -// Assert.Equal(1, ptr[0]); -// Assert.Equal(2, ptr[1]); -// Assert.Equal(3, ptr[2]); -// } - -// [Theory] -// [MemberData(nameof(ColorData))] -// public void Equals_WhenTrue(byte r, byte g, byte b) -// { -// var x = new Rgb24(r, g, b); -// var y = new Rgb24(r, g, b); - -// Assert.True(x.Equals(y)); -// Assert.True(x.Equals((object)y)); -// Assert.Equal(x.GetHashCode(), y.GetHashCode()); -// } - -// [Theory] -// [InlineData(1, 2, 3, 1, 2, 4)] -// [InlineData(0, 255, 0, 0, 244, 0)] -// [InlineData(1, 255, 0, 0, 255, 0)] -// public void Equals_WhenFalse(byte r1, byte g1, byte b1, byte r2, byte g2, byte b2) -// { -// var a = new Rgb24(r1, g1, b1); -// var b = new Rgb24(r2, g2, b2); - -// Assert.False(a.Equals(b)); -// Assert.False(a.Equals((object)b)); -// } - -// [Fact] -// public void PackFromRgba32() -// { -// var rgb = default(Rgb24); -// rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); - -// Assert.Equal(1, rgb.R); -// Assert.Equal(2, rgb.G); -// Assert.Equal(3, rgb.B); -// } - -// private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new Vector4( -// r / 255f, -// g / 255f, -// b / 255f, -// a / 255f); - -// [Fact] -// public void PackFromVector4() -// { -// var rgb = default(Rgb24); -// rgb.PackFromVector4(Vec(1, 2, 3, 4)); - -// Assert.Equal(1, rgb.R); -// Assert.Equal(2, rgb.G); -// Assert.Equal(3, rgb.B); -// } - -// [Fact] -// public void ToVector4() -// { -// var rgb = new Rgb24(1, 2, 3); - -// Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); -// } - -// [Fact] -// public void ToRgb24() -// { -// var rgb = new Rgb24(1, 2, 3); -// var dest = default(Rgb24); - -// rgb.ToRgb24(ref dest); - -// Assert.Equal(rgb, dest); -// } - -// [Fact] -// public void ToRgba32() -// { -// var rgb = new Rgb24(1, 2, 3); -// var rgba = default(Rgba32); - -// rgb.ToRgba32(ref rgba); - -// Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); -// } - -// [Fact] -// public void ToBgr24() -// { -// var rgb = new Rgb24(1, 2, 3); -// var bgr = default(Bgr24); - -// rgb.ToBgr24(ref bgr); - -// Assert.Equal(new Bgr24(1, 2, 3), bgr); -// } - -// [Fact] -// public void ToBgra32() -// { -// var rgb = new Rgb24(1, 2, 3); -// var bgra = default(Bgra32); - -// rgb.ToBgra32(ref bgra); - -// Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); -// } - -// [Fact] -// public void Rgb24_PackFromRgb48_ToRgb48() -// { -// // arrange -// var input = default(Rgb24); -// var actual = default(Rgb48); -// var expected = new Rgb48(65535, 0, 65535); - -// // act -// input.PackFromRgb48(expected); -// input.ToRgb48(ref actual); - -// // assert -// Assert.Equal(expected, actual); -// } - -// [Fact] -// public void Rgb24_PackFromRgba64_ToRgba64() -// { -// // arrange -// var input = default(Rgb24); -// var actual = default(Rgba64); -// var expected = new Rgba64(65535, 0, 65535, 65535); - -// // act -// input.PackFromRgba64(expected); -// input.ToRgba64(ref actual); - -// // assert -// Assert.Equal(expected, actual); -// } -// } -//} \ No newline at end of file +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.PixelFormats +{ + public class Rgb24Tests + { + public static readonly TheoryData ColorData = + new TheoryData() + { + { 1, 2, 3 }, + { 4, 5, 6 }, + { 0, 255, 42 } + }; + + [Theory] + [MemberData(nameof(ColorData))] + public void Constructor(byte r, byte g, byte b) + { + var p = new Rgb24(r, g, b); + + Assert.Equal(r, p.R); + Assert.Equal(g, p.G); + Assert.Equal(b, p.B); + } + + [Fact] + public unsafe void ByteLayoutIsSequentialRgb() + { + var color = new Rgb24(1, 2, 3); + byte* ptr = (byte*)&color; + + Assert.Equal(1, ptr[0]); + Assert.Equal(2, ptr[1]); + Assert.Equal(3, ptr[2]); + } + + [Theory] + [MemberData(nameof(ColorData))] + public void Equals_WhenTrue(byte r, byte g, byte b) + { + var x = new Rgb24(r, g, b); + var y = new Rgb24(r, g, b); + + Assert.True(x.Equals(y)); + Assert.True(x.Equals((object)y)); + Assert.Equal(x.GetHashCode(), y.GetHashCode()); + } + + [Theory] + [InlineData(1, 2, 3, 1, 2, 4)] + [InlineData(0, 255, 0, 0, 244, 0)] + [InlineData(1, 255, 0, 0, 255, 0)] + public void Equals_WhenFalse(byte r1, byte g1, byte b1, byte r2, byte g2, byte b2) + { + var a = new Rgb24(r1, g1, b1); + var b = new Rgb24(r2, g2, b2); + + Assert.False(a.Equals(b)); + Assert.False(a.Equals((object)b)); + } + + [Fact] + public void PackFromRgba32() + { + var rgb = default(Rgb24); + rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); + + Assert.Equal(1, rgb.R); + Assert.Equal(2, rgb.G); + Assert.Equal(3, rgb.B); + } + + private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new Vector4( + r / 255f, + g / 255f, + b / 255f, + a / 255f); + + [Fact] + public void PackFromVector4() + { + var rgb = default(Rgb24); + rgb.PackFromVector4(Vec(1, 2, 3, 4)); + + Assert.Equal(1, rgb.R); + Assert.Equal(2, rgb.G); + Assert.Equal(3, rgb.B); + } + + [Fact] + public void ToVector4() + { + var rgb = new Rgb24(1, 2, 3); + + Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); + } + + [Fact] + public void ToRgba32() + { + var rgb = new Rgb24(1, 2, 3); + var rgba = rgb.ToRgba32(); + + Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index 2af488e3cd..16dfd7f577 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -1,192 +1,61 @@ -//// Copyright (c) Six Labors and contributors. -//// Licensed under the Apache License, Version 2.0. - -//using System.Numerics; -//using SixLabors.ImageSharp.PixelFormats; -//using Xunit; - -//namespace SixLabors.ImageSharp.Tests.PixelFormats -//{ -// public class Rgb48Tests -// { -// [Fact] -// public void Rgb48_Values() -// { -// var rgb = new Rgba64(5243, 9830, 19660, 29491); - -// Assert.Equal(5243, rgb.R); -// Assert.Equal(9830, rgb.G); -// Assert.Equal(19660, rgb.B); -// Assert.Equal(29491, rgb.A); -// } - -// [Fact] -// public void Rgb48_ToVector4() -// { -// Assert.Equal(new Vector4(0, 0, 0, 1), new Rgb48(0, 0, 0, 0).ToVector4()); -// Assert.Equal(Vector4.One, new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue).ToVector4()); -// } - -// [Fact] -// public void Rgb48_ToScaledVector4() -// { -// // arrange -// var short2 = new Rgb48(Vector3.One); - -// // act -// Vector4 actual = short2.ToScaledVector4(); - -// // assert -// Assert.Equal(1, actual.X); -// Assert.Equal(1, actual.Y); -// Assert.Equal(1, actual.Z); -// Assert.Equal(1, actual.W); -// } - -// [Fact] -// public void Rgb48_PackFromScaledVector4() -// { -// // arrange -// var pixel = default(Rgb48); -// var short3 = new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); -// var expected = new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); - -// // act -// Vector4 scaled = short3.ToScaledVector4(); -// pixel.PackFromScaledVector4(scaled); - -// // assert -// Assert.Equal(expected, pixel); -// } - -// //[Fact] -// //public void Rgb48_Clamping() -// //{ -// // Assert.Equal(new Vector4(0, 0, 0, 1), new Rgb48(Vector3.One * -1234.0f).ToVector4()); -// // Assert.Equal(Vector4.One, new Rgb48(Vector3.One * 1234.0f).ToVector4()); -// //} - -// //[Fact] -// //public void Rgb48_ToRgb24() -// //{ -// // // arrange -// // var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); -// // var actual = default(Rgb24); -// // var expected = new Rgb24(20, 38, 76); - -// // // act -// // rgba48.ToRgb24(ref actual); - -// // // assert -// // Assert.Equal(expected, actual); -// //} - -// //[Fact] -// //public void Rgb48_ToRgba32() -// //{ -// // // arrange -// // var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); -// // var actual = default(Rgba32); -// // var expected = new Rgba32(20, 38, 76, 255); - -// // // act -// // rgba48.ToRgba32(ref actual); - -// // // assert -// // Assert.Equal(expected, actual); -// //} - -// //[Fact] -// //public void Rgb48_ToArgb32() -// //{ -// // // arrange -// // var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); -// // var actual = default(Argb32); -// // var expected = new Argb32(20, 38, 76, 255); - -// // // act -// // rgba48.ToArgb32(ref actual); - -// // // assert -// // Assert.Equal(expected, actual); -// //} - -// //[Fact] -// //public void Rgba64_ToBgr24() -// //{ -// // // arrange -// // var rgb48 = new Rgb48(0.08f, 0.15f, 0.30f); -// // var actual = default(Bgr24); -// // var expected = new Bgr24(20, 38, 76); - -// // // act -// // rgb48.ToBgr24(ref actual); - -// // // assert -// // Assert.Equal(expected, actual); -// //} - -// //[Fact] -// //public void Rgb48_ToBgra32() -// //{ -// // // arrange -// // var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); -// // var actual = default(Bgra32); -// // var expected = new Bgra32(20, 38, 76, 255); - -// // // act -// // rgba48.ToBgra32(ref actual); - -// // // assert -// // Assert.Equal(expected, actual); -// //} - -// //[Fact] -// //public void Rgb48_PackFromRgba32_ToRgba32() -// //{ -// // // arrange -// // var rgb48 = default(Rgb48); -// // var actual = default(Rgba32); -// // var expected = new Rgba32(20, 38, 76, 255); - -// // // act -// // rgb48.PackFromRgba32(expected); -// // rgb48.ToRgba32(ref actual); - -// // // assert -// // Assert.Equal(expected, actual); -// //} - -// //[Fact] -// //public void Rgb48_PackFromRgb48_ToRgb48() -// //{ -// // // arrange -// // var input = default(Rgb48); -// // var actual = default(Rgb48); -// // var expected = new Rgb48(65535, 0, 65535); - -// // // act -// // input.PackFromRgb48(expected); -// // input.ToRgb48(ref actual); - -// // // assert -// // Assert.Equal(expected, actual); -// //} - -// //[Fact] -// //public void Rgb48_PackFromRgba64_ToRgba64() -// //{ -// // // arrange -// // var input = default(Rgb48); -// // var actual = default(Rgba64); -// // var expected = new Rgba64(65535, 0, 65535, 65535); - -// // // act -// // input.PackFromRgba64(expected); -// // input.ToRgba64(ref actual); - -// // // assert -// // Assert.Equal(expected, actual); -// //} -// } -//} +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.PixelFormats +{ + public class Rgb48Tests + { + [Fact] + public void Rgb48_Values() + { + var rgb = new Rgba64(5243, 9830, 19660, 29491); + + Assert.Equal(5243, rgb.R); + Assert.Equal(9830, rgb.G); + Assert.Equal(19660, rgb.B); + Assert.Equal(29491, rgb.A); + } + + [Fact] + public void Rgb48_ToVector4() + => Assert.Equal(Vector4.One, new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue).ToVector4()); + + [Fact] + public void Rgb48_ToScaledVector4() + => Assert.Equal(Vector4.One, new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue).ToVector4()); + + [Fact] + public void Rgb48_PackFromScaledVector4() + { + // arrange + var pixel = default(Rgb48); + var short3 = new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); + var expected = new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); + + // act + Vector4 scaled = short3.ToScaledVector4(); + pixel.PackFromScaledVector4(scaled); + + // assert + Assert.Equal(expected, pixel); + } + + [Fact] + public void Rgb48_ToRgba32() + { + // arrange + var rgba48 = new Rgb48(5140, 9766, 19532); + var expected = new Rgba32(20, 38, 76, 255); + + // act + var actual = rgba48.ToRgba32(); + + // assert + Assert.Equal(expected, actual); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs index d8ad6d3f1e..243d4a44c9 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs @@ -71,144 +71,18 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One, new Rgba1010102(Vector4.One * 1234.0f).ToVector4()); } - //[Fact] - //public void Rgba1010102_ToRgb24() - //{ - // // arrange - // var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Rgb24); - // var expected = new Rgb24(25, 0, 128); - - // // act - // rgba.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rgba1010102_ToRgba32() - //{ - // // arrange - // var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Rgba32); - // var expected = new Rgba32(25, 0, 128, 0); - - // // act - // rgba.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rgba1010102_ToBgr24() - //{ - // // arrange - // var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Bgr24); - // var expected = new Bgr24(25, 0, 128); - - // // act - // rgba.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rgba1010102_ToBgra32() - //{ - // // arrange - // var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Bgra32); - // var expected = new Bgra32(25, 0, 128, 0); - - // // act - // rgba.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rgba1010102_PackFromRgba32_ToRgba32() - //{ - // // arrange - // var rgba = default(Rgba1010102); - // var expected = new Rgba32(25, 0, 128, 0); - // var actual = default(Rgba32); - - // // act - // rgba.PackFromRgba32(expected); - // rgba.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rgba1010102_PackFromBgra32_ToBgra32() - //{ - // // arrange - // var rgba = default(Rgba1010102); - // var expected = new Bgra32(25, 0, 128, 0); - // var actual = default(Bgra32); - - // // act - // rgba.PackFromBgra32(expected); - // rgba.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rgba1010102_PackFromArgb32_ToArgb32() - //{ - // // arrange - // var rgba = default(Rgba1010102); - // var expected = new Argb32(25, 0, 128, 0); - // var actual = default(Argb32); - - // // act - // rgba.PackFromArgb32(expected); - // rgba.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rgba1010102_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(Rgba1010102); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 0, 65535); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rgba1010102_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(Rgba1010102); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 0, 65535, 65535); + [Fact] + public void Rgba1010102_ToRgba32() + { + // arrange + var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); + var expected = new Rgba32(25, 0, 128, 0); - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); + // act + var actual = rgba.ToRgba32(); - // // assert - // Assert.Equal(expected, actual); - //} + // assert + Assert.Equal(expected, actual); + } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index 185fc5635d..e9ac5377d2 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -77,70 +77,19 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One, one.ToVector4()); } - //[Fact] - //public void Rgba64_ToRgba32() - //{ - // // arrange - // var rgba64 = new Rgba64( - // (ushort)(0.08f * ushort.MaxValue), - // (ushort)(0.15f * ushort.MaxValue), - // (ushort)(0.30f * ushort.MaxValue), - // (ushort)(0.45f * ushort.MaxValue)); - // var actual = default(Rgba32); - // var expected = new Rgba32(20, 38, 76, 115); - - // // act - // actual = rgba64.ToRgba32(); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rgba64_PackFromRgba32_ToRgba32() - //{ - // // arrange - // var rgba64 = default(Rgba64); - // var actual = default(Rgba32); - // var expected = new Rgba32(20, 38, 76, 115); - - // // act - // rgba64.PackFromRgba32(expected); - // actual = rgba64.ToRgba32(); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rgb48_PackFromRgb48() - //{ - // // arrange - // var input = default(Rgba64); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 0, 65535); - - // // act - // input.PackFromRgb48(expected); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rgba64_PackFromRgba64() - //{ - // // arrange - // var input = default(Rgba64); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 0, 65535, 0); + [Fact] + public void Rgba64_ToRgba32() + { + // arrange + var rgba64 = new Rgba64(5140, 9766, 19532, 29555); + var actual = default(Rgba32); + var expected = new Rgba32(20, 38, 76, 115); - // // act - // input.PackFromRgba64(expected); - // actual.PackFromScaledVector4(input.ToScaledVector4()); + // act + actual = rgba64.ToRgba32(); - // // assert - // Assert.Equal(expected, actual); - //} + // assert + Assert.Equal(expected, actual); + } } } diff --git a/tests/Images/External b/tests/Images/External index 1a807d17b4..ee90e5f322 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 1a807d17b4cf5ab50558983d4137614cabe96ce3 +Subproject commit ee90e5f32218027744b5d40058b587cc1047b76f From 260a8f8c9a3d0730e836a606e10e5802d5b0fe1e Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 14 Oct 2018 22:43:02 +0200 Subject: [PATCH 144/381] BulkConvertByteToNormalizedFloat --- src/ImageSharp/Common/Extensions/SimdUtils.cs | 75 +- .../PixelFormats/Rgba32.PixelOperations.cs | 12 +- .../Color/Bulk/ToVector4.cs | 31 +- .../PixelFormats/PixelOperationsTests.cs | 1384 +++++++++-------- 4 files changed, 802 insertions(+), 700 deletions(-) diff --git a/src/ImageSharp/Common/Extensions/SimdUtils.cs b/src/ImageSharp/Common/Extensions/SimdUtils.cs index 7b77fefcac..db1e80dda2 100644 --- a/src/ImageSharp/Common/Extensions/SimdUtils.cs +++ b/src/ImageSharp/Common/Extensions/SimdUtils.cs @@ -7,6 +7,8 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.PixelFormats; + namespace SixLabors.ImageSharp { /// @@ -103,6 +105,47 @@ namespace SixLabors.ImageSharp } } + internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + { + if (!Vector.IsHardwareAccelerated) + { + throw new InvalidOperationException( + "Rgba32.PixelOperations.ToVector4SimdAligned() should not be called when Vector.IsHardwareAccelerated == false!"); + } + + DebugGuard.IsTrue((dest.Length % Vector.Count) == 0, nameof(source), "dest.Length should be divisable by Vector.Count!"); + + var bVec = new Vector(256.0f / 255.0f); + var magicFloat = new Vector(32768.0f); + var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f + var mask = new Vector(255); + + ref Octet.OfByte sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref Octet.OfUInt32 destBaseAsWideOctet = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + + ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsWideOctet); + + int n = dest.Length / 8; + Octet.OfUInt32 temp = default; + + for (int i = 0; i < n; i++) + { + Octet.OfByte sVal = Unsafe.Add(ref sourceBase, i); + + // This call is the bottleneck now: + temp.LoadFrom(ref sVal); + + Vector vi = Unsafe.As>(ref temp); + vi &= mask; + vi |= magicInt; + + var vf = Vector.AsVectorSingle(vi); + vf = (vf - magicFloat) * bVec; + + Unsafe.Add(ref destBaseAsFloat, i) = vf; + } + } + /// /// Same as but clamps overflown values before conversion. /// @@ -181,6 +224,19 @@ namespace SixLabors.ImageSharp { return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]"; } + + [MethodImpl(InliningOptions.ShortMethod)] + public void LoadFrom(ref OfByte src) + { + this.V0 = src.V0; + this.V1 = src.V1; + this.V2 = src.V2; + this.V3 = src.V3; + this.V4 = src.V4; + this.V5 = src.V5; + this.V6 = src.V6; + this.V7 = src.V7; + } } [StructLayout(LayoutKind.Explicit, Size = 8)] @@ -215,16 +271,17 @@ namespace SixLabors.ImageSharp return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]"; } - public void LoadFrom(ref OfUInt32 i) + [MethodImpl(InliningOptions.ShortMethod)] + public void LoadFrom(ref OfUInt32 src) { - this.V0 = (byte)i.V0; - this.V1 = (byte)i.V1; - this.V2 = (byte)i.V2; - this.V3 = (byte)i.V3; - this.V4 = (byte)i.V4; - this.V5 = (byte)i.V5; - this.V6 = (byte)i.V6; - this.V7 = (byte)i.V7; + this.V0 = (byte)src.V0; + this.V1 = (byte)src.V1; + this.V2 = (byte)src.V2; + this.V3 = (byte)src.V3; + this.V4 = (byte)src.V4; + this.V5 = (byte)src.V5; + this.V6 = (byte)src.V6; + this.V7 = (byte)src.V7; } } } diff --git a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs index 2629ce3f79..76e119ba44 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs @@ -57,14 +57,14 @@ namespace SixLabors.ImageSharp.PixelFormats int unpackedRawCount = count * 4; ref uint sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference(sourceColors)); - ref UnpackedRGBA destBaseAsUnpacked = ref Unsafe.As(ref MemoryMarshal.GetReference(destVectors)); - ref Vector destBaseAsUInt = ref Unsafe.As>(ref destBaseAsUnpacked); - ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsUnpacked); + ref WideRgba destBaseAsWide = ref Unsafe.As(ref MemoryMarshal.GetReference(destVectors)); + ref Vector destBaseAsUInt = ref Unsafe.As>(ref destBaseAsWide); + ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsWide); for (int i = 0; i < count; i++) { uint sVal = Unsafe.Add(ref sourceBase, i); - ref UnpackedRGBA dst = ref Unsafe.Add(ref destBaseAsUnpacked, i); + ref WideRgba dst = ref Unsafe.Add(ref destBaseAsWide, i); // This call is the bottleneck now: dst.Load(sVal); @@ -174,10 +174,10 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// Value type to store -s unpacked into multiple -s. + /// Value type to store -s widened into multiple -s. /// [StructLayout(LayoutKind.Sequential)] - private struct UnpackedRGBA + private struct WideRgba { private uint r; diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 50fac25139..7b6f902d82 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -6,8 +6,13 @@ using System.Buffers; using System; using System.Numerics; +using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes.Jobs; +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Environments; +using BenchmarkDotNet.Jobs; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -17,11 +22,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk public abstract class ToVector4 where TPixel : struct, IPixel { - private IMemoryOwner source; + protected IMemoryOwner source; - private IMemoryOwner destination; + protected IMemoryOwner destination; - [Params(64, 300, 1024)] + [Params( + //64, + 1024)] public int Count { get; set; } [GlobalSetup] @@ -38,7 +45,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.destination.Dispose(); } - [Benchmark(Baseline = true)] + [Benchmark] public void PerElement() { Span s = this.source.GetSpan(); @@ -51,7 +58,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - [Benchmark] + [Benchmark(Baseline = true)] public void CommonBulk() { new PixelOperations().ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); @@ -64,7 +71,21 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } + [CoreJob] + //[ClrJob] public class ToVector4_Rgba32 : ToVector4 { + class Config : ManualConfig + { + } + + [Benchmark] + public void BulkConvertByteToNormalizedFloat() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 9e41fd94f3..a96da03e7f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -1,93 +1,117 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Buffers; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; -using Xunit.Abstractions; - -namespace SixLabors.ImageSharp.Tests.PixelFormats -{ - public partial class PixelOperationsTests - { - public class Rgba32 : PixelOperationsTests - { - public Rgba32(ITestOutputHelper output) - : base(output) - { - } - - // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - - [Fact] - public void IsSpecialImplementation() - { - Assert.IsType(PixelOperations.Instance); - } - - [Fact] - public void ToVector4SimdAligned() - { - if (!Vector.IsHardwareAccelerated) - { - return; - } - - ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(64); - Vector4[] expected = CreateExpectedVector4Data(source); - - TestOperation( - source, - expected, - (s, d) => ImageSharp.PixelFormats.Rgba32.PixelOperations.ToVector4SimdAligned(s, d.GetSpan(), 64) - ); - } - - - // [Fact] // Profiling benchmark - enable manually! -#pragma warning disable xUnit1013 // Public method should be marked as test - public void Benchmark_ToVector4() -#pragma warning restore xUnit1013 // Public method should be marked as test - { - int times = 200000; - int count = 1024; - - using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) - using (IMemoryOwner dest = Configuration.Default.MemoryAllocator.Allocate(count)) - { - this.Measure( - times, - () => - { - PixelOperations.Instance.ToVector4(source.GetSpan(), dest.GetSpan(), count); - }); - } - } - } - - public class Argb32 : PixelOperationsTests - { - // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: - public Argb32(ITestOutputHelper output) - : base(output) - { - } - - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - } - - [Theory] - [WithBlankImages(1, 1, PixelTypes.All)] - public void GetGlobalInstance(TestImageProvider dummy) - where TPixel : struct, IPixel - { - Assert.NotNull(PixelOperations.Instance); +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats +{ + public partial class PixelOperationsTests + { + public class Rgba32 : PixelOperationsTests + { + public Rgba32(ITestOutputHelper output) + : base(output) + { + } + + // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + [Fact] + public void IsSpecialImplementation() + { + Assert.IsType(PixelOperations.Instance); + } + + [Fact] + public void ToVector4SimdAligned() + { + if (!Vector.IsHardwareAccelerated) + { + return; + } + + ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(64); + Vector4[] expected = CreateExpectedVector4Data(source); + + TestOperation( + source, + expected, + (s, d) => ImageSharp.PixelFormats.Rgba32.PixelOperations.ToVector4SimdAligned(s, d.GetSpan(), 64) + ); + } + + [Fact] + public void BulkConvertByteToNormalizedFloat() + { + if (!Vector.IsHardwareAccelerated) + { + return; + } + + ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(64); + Vector4[] expected = CreateExpectedVector4Data(source); + + TestOperation( + source, + expected, + (s, d) => + { + ReadOnlySpan sBytes = MemoryMarshal.Cast(s); + Span dFloats = MemoryMarshal.Cast(d.Memory.Span); + + SimdUtils.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + } + ); + } + + + // [Fact] // Profiling benchmark - enable manually! +#pragma warning disable xUnit1013 // Public method should be marked as test + public void Benchmark_ToVector4() +#pragma warning restore xUnit1013 // Public method should be marked as test + { + int times = 200000; + int count = 1024; + + using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) + using (IMemoryOwner dest = Configuration.Default.MemoryAllocator.Allocate(count)) + { + this.Measure( + times, + () => + { + PixelOperations.Instance.ToVector4(source.GetSpan(), dest.GetSpan(), count); + }); + } + } + } + + public class Argb32 : PixelOperationsTests + { + // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: + public Argb32(ITestOutputHelper output) + : base(output) + { + } + + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + } + + [Theory] + [WithBlankImages(1, 1, PixelTypes.All)] + public void GetGlobalInstance(TestImageProvider dummy) + where TPixel : struct, IPixel + { + Assert.NotNull(PixelOperations.Instance); } [Fact] @@ -99,594 +123,594 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.False(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Transparent)); Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Lighten, 1).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal,PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); - } - } - - public abstract class PixelOperationsTests : MeasureFixture - where TPixel : struct, IPixel - { - protected PixelOperationsTests(ITestOutputHelper output) - : base(output) - { - } - - public static TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - - private static PixelOperations Operations => PixelOperations.Instance; - - internal static TPixel[] CreateExpectedPixelData(Vector4[] source) - { - var expected = new TPixel[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i].PackFromVector4(source[i]); - } - return expected; - } - - internal static TPixel[] CreateScaledExpectedPixelData(Vector4[] source) - { - var expected = new TPixel[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i].PackFromScaledVector4(source[i]); - } - return expected; - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromVector4(int count) - { - Vector4[] source = CreateVector4TestData(count); - TPixel[] expected = CreateExpectedPixelData(source); - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromVector4(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromScaledVector4(int count) - { - Vector4[] source = CreateVector4TestData(count); - TPixel[] expected = CreateScaledExpectedPixelData(source); - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromScaledVector4(s, d.GetSpan(), count) - ); - } - - internal static Vector4[] CreateExpectedVector4Data(TPixel[] source) - { - var expected = new Vector4[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i] = source[i].ToVector4(); - } - return expected; - } - - internal static Vector4[] CreateExpectedScaledVector4Data(TPixel[] source) - { - var expected = new Vector4[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i] = source[i].ToScaledVector4(); - } - return expected; - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToVector4(int count) - { - TPixel[] source = CreatePixelTestData(count); - Vector4[] expected = CreateExpectedVector4Data(source); - - TestOperation( - source, - expected, - (s, d) => Operations.ToVector4(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToScaledVector4(int count) - { - TPixel[] source = CreateScaledPixelTestData(count); - Vector4[] expected = CreateExpectedScaledVector4Data(source); - - TestOperation( - source, - expected, - (s, d) => Operations.ToScaledVector4(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromRgb24Bytes(int count) - { - byte[] source = CreateByteTestData(count * 3); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i3 = i * 3; - - expected[i].PackFromRgba32(new Rgba32(source[i3 + 0], source[i3 + 1], source[i3 + 2], 255)); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromRgb24Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToRgb24Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 3]; - var rgb = default(Rgb24); - - for (int i = 0; i < count; i++) - { - int i3 = i * 3; - source[i].ToRgb24(ref rgb); - expected[i3] = rgb.R; - expected[i3 + 1] = rgb.G; - expected[i3 + 2] = rgb.B; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToRgb24Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromRgba32Bytes(int count) - { - byte[] source = CreateByteTestData(count * 4); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - - expected[i].PackFromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromRgba32Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToRgba32Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var rgba = default(Rgba32); - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - source[i].ToRgba32(ref rgba); - expected[i4] = rgba.R; - expected[i4 + 1] = rgba.G; - expected[i4 + 2] = rgba.B; - expected[i4 + 3] = rgba.A; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToRgba32Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromRgb48Bytes(int count) - { - byte[] source = CreateByteTestData(count * 6); - Span sourceSpan = source.AsSpan(); - var expected = new TPixel[count]; - - var rgba64 = new Rgba64(0, 0, 0, 65535); - for (int i = 0; i < count; i++) - { - int i6 = i * 6; - rgba64.Rgb = MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]; - expected[i].PackFromRgba64(rgba64); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromRgb48Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToRgb48Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 6]; - Rgb48 rgb = default; - - for (int i = 0; i < count; i++) - { - int i6 = i * 6; - source[i].ToRgb48(ref rgb); - Rgba64Bytes rgb48Bytes = Unsafe.As(ref rgb); - expected[i6] = rgb48Bytes[0]; - expected[i6 + 1] = rgb48Bytes[1]; - expected[i6 + 2] = rgb48Bytes[2]; - expected[i6 + 3] = rgb48Bytes[3]; - expected[i6 + 4] = rgb48Bytes[4]; - expected[i6 + 5] = rgb48Bytes[5]; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToRgb48Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromRgba64Bytes(int count) - { - byte[] source = CreateByteTestData(count * 8); - Span sourceSpan = source.AsSpan(); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i8 = i * 8; - expected[i].PackFromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromRgba64Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToRgba64Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 8]; - Rgba64 rgba = default; - - for (int i = 0; i < count; i++) - { - int i8 = i * 8; - source[i].ToRgba64(ref rgba); - Rgba64Bytes rgba64Bytes = Unsafe.As(ref rgba); - expected[i8] = rgba64Bytes[0]; - expected[i8 + 1] = rgba64Bytes[1]; - expected[i8 + 2] = rgba64Bytes[2]; - expected[i8 + 3] = rgba64Bytes[3]; - expected[i8 + 4] = rgba64Bytes[4]; - expected[i8 + 5] = rgba64Bytes[5]; - expected[i8 + 6] = rgba64Bytes[6]; - expected[i8 + 7] = rgba64Bytes[7]; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToRgba64Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromBgr24Bytes(int count) - { - byte[] source = CreateByteTestData(count * 3); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i3 = i * 3; - - expected[i].PackFromRgba32(new Rgba32(source[i3 + 2], source[i3 + 1], source[i3 + 0], 255)); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromBgr24Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToBgr24Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 3]; - var bgr = default(Bgr24); - - for (int i = 0; i < count; i++) - { - int i3 = i * 3; - source[i].ToBgr24(ref bgr); - expected[i3] = bgr.B; - expected[i3 + 1] = bgr.G; - expected[i3 + 2] = bgr.R; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToBgr24Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromBgra32Bytes(int count) - { - byte[] source = CreateByteTestData(count * 4); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - - expected[i].PackFromRgba32(new Rgba32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromBgra32Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToZyxwBytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var bgra = default(Bgra32); - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - source[i].ToBgra32(ref bgra); - expected[i4] = bgra.B; - expected[i4 + 1] = bgra.G; - expected[i4 + 2] = bgra.R; - expected[i4 + 3] = bgra.A; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToBgra32Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromArgb32Bytes(int count) - { - byte[] source = CreateByteTestData(count * 4); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - - expected[i].PackFromRgba32(new Rgba32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromArgb32Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToArgb32Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var argb = default(Argb32); - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - source[i].ToArgb32(ref argb); - expected[i4] = argb.A; - expected[i4 + 1] = argb.R; - expected[i4 + 2] = argb.G; - expected[i4 + 3] = argb.B; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToArgb32Bytes(s, d.GetSpan(), count) - ); - } - - private class TestBuffers : IDisposable - where TSource : struct - where TDest : struct - { - public TSource[] SourceBuffer { get; } - public IMemoryOwner ActualDestBuffer { get; } - public TDest[] ExpectedDestBuffer { get; } - - public TestBuffers(TSource[] source, TDest[] expectedDest) - { - this.SourceBuffer = source; - this.ExpectedDestBuffer = expectedDest; - this.ActualDestBuffer = Configuration.Default.MemoryAllocator.Allocate(expectedDest.Length); - } - - public void Dispose() - { - this.ActualDestBuffer.Dispose(); - } - - private const float Tolerance = 0.0001f; - - public void Verify() - { - int count = this.ExpectedDestBuffer.Length; - - if (typeof(TDest) == typeof(Vector4)) - { - - Span expected = MemoryMarshal.Cast(this.ExpectedDestBuffer.AsSpan()); - Span actual = MemoryMarshal.Cast(this.ActualDestBuffer.GetSpan()); - - for (int i = 0; i < count; i++) - { - // ReSharper disable PossibleNullReferenceException - Assert.Equal(expected[i], actual[i], new ApproximateFloatComparer(0.001f)); - // ReSharper restore PossibleNullReferenceException - } - } - else - { - Span expected = this.ExpectedDestBuffer.AsSpan(); - Span actual = this.ActualDestBuffer.GetSpan(); - for (int i = 0; i < count; i++) - { - Assert.Equal(expected[i], actual[i]); - } - } - } - } - - internal static void TestOperation( - TSource[] source, - TDest[] expected, - Action> action) - where TSource : struct - where TDest : struct - { - using (var buffers = new TestBuffers(source, expected)) - { - action(buffers.SourceBuffer, buffers.ActualDestBuffer); - buffers.Verify(); - } - } - - internal static Vector4[] CreateVector4TestData(int length) - { - var result = new Vector4[length]; - var rnd = new Random(42); // Deterministic random values - - for (int i = 0; i < result.Length; i++) - { - result[i] = GetVector(rnd); - } - return result; - } - - internal static TPixel[] CreatePixelTestData(int length) - { - var result = new TPixel[length]; - - var rnd = new Random(42); // Deterministic random values - - for (int i = 0; i < result.Length; i++) - { - Vector4 v = GetVector(rnd); - result[i].PackFromVector4(v); - } - - return result; - } - - internal static TPixel[] CreateScaledPixelTestData(int length) - { - var result = new TPixel[length]; - - var rnd = new Random(42); // Deterministic random values - - for (int i = 0; i < result.Length; i++) - { - Vector4 v = GetVector(rnd); - result[i].PackFromScaledVector4(v); - } - - return result; - } - - internal static byte[] CreateByteTestData(int length) - { - byte[] result = new byte[length]; - var rnd = new Random(42); // Deterministic random values - - for (int i = 0; i < result.Length; i++) - { - result[i] = (byte)rnd.Next(255); - } - return result; - } - - internal static Vector4 GetVector(Random rnd) - { - return new Vector4( - (float)rnd.NextDouble(), - (float)rnd.NextDouble(), - (float)rnd.NextDouble(), - (float)rnd.NextDouble() - ); - } - - [StructLayout(LayoutKind.Sequential)] - private unsafe struct Rgba64Bytes - { - public fixed byte Data[8]; - - public byte this[int idx] - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - ref byte self = ref Unsafe.As(ref this); - return Unsafe.Add(ref self, idx); - } - } - } - } + } + } + + public abstract class PixelOperationsTests : MeasureFixture + where TPixel : struct, IPixel + { + protected PixelOperationsTests(ITestOutputHelper output) + : base(output) + { + } + + public static TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + private static PixelOperations Operations => PixelOperations.Instance; + + internal static TPixel[] CreateExpectedPixelData(Vector4[] source) + { + var expected = new TPixel[source.Length]; + + for (int i = 0; i < expected.Length; i++) + { + expected[i].PackFromVector4(source[i]); + } + return expected; + } + + internal static TPixel[] CreateScaledExpectedPixelData(Vector4[] source) + { + var expected = new TPixel[source.Length]; + + for (int i = 0; i < expected.Length; i++) + { + expected[i].PackFromScaledVector4(source[i]); + } + return expected; + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromVector4(int count) + { + Vector4[] source = CreateVector4TestData(count); + TPixel[] expected = CreateExpectedPixelData(source); + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromVector4(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromScaledVector4(int count) + { + Vector4[] source = CreateVector4TestData(count); + TPixel[] expected = CreateScaledExpectedPixelData(source); + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromScaledVector4(s, d.GetSpan(), count) + ); + } + + internal static Vector4[] CreateExpectedVector4Data(TPixel[] source) + { + var expected = new Vector4[source.Length]; + + for (int i = 0; i < expected.Length; i++) + { + expected[i] = source[i].ToVector4(); + } + return expected; + } + + internal static Vector4[] CreateExpectedScaledVector4Data(TPixel[] source) + { + var expected = new Vector4[source.Length]; + + for (int i = 0; i < expected.Length; i++) + { + expected[i] = source[i].ToScaledVector4(); + } + return expected; + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToVector4(int count) + { + TPixel[] source = CreatePixelTestData(count); + Vector4[] expected = CreateExpectedVector4Data(source); + + TestOperation( + source, + expected, + (s, d) => Operations.ToVector4(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToScaledVector4(int count) + { + TPixel[] source = CreateScaledPixelTestData(count); + Vector4[] expected = CreateExpectedScaledVector4Data(source); + + TestOperation( + source, + expected, + (s, d) => Operations.ToScaledVector4(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromRgb24Bytes(int count) + { + byte[] source = CreateByteTestData(count * 3); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i3 = i * 3; + + expected[i].PackFromRgba32(new Rgba32(source[i3 + 0], source[i3 + 1], source[i3 + 2], 255)); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromRgb24Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToRgb24Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 3]; + var rgb = default(Rgb24); + + for (int i = 0; i < count; i++) + { + int i3 = i * 3; + source[i].ToRgb24(ref rgb); + expected[i3] = rgb.R; + expected[i3 + 1] = rgb.G; + expected[i3 + 2] = rgb.B; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToRgb24Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromRgba32Bytes(int count) + { + byte[] source = CreateByteTestData(count * 4); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + + expected[i].PackFromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromRgba32Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToRgba32Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 4]; + var rgba = default(Rgba32); + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + source[i].ToRgba32(ref rgba); + expected[i4] = rgba.R; + expected[i4 + 1] = rgba.G; + expected[i4 + 2] = rgba.B; + expected[i4 + 3] = rgba.A; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToRgba32Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromRgb48Bytes(int count) + { + byte[] source = CreateByteTestData(count * 6); + Span sourceSpan = source.AsSpan(); + var expected = new TPixel[count]; + + var rgba64 = new Rgba64(0, 0, 0, 65535); + for (int i = 0; i < count; i++) + { + int i6 = i * 6; + rgba64.Rgb = MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]; + expected[i].PackFromRgba64(rgba64); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromRgb48Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToRgb48Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 6]; + Rgb48 rgb = default; + + for (int i = 0; i < count; i++) + { + int i6 = i * 6; + source[i].ToRgb48(ref rgb); + Rgba64Bytes rgb48Bytes = Unsafe.As(ref rgb); + expected[i6] = rgb48Bytes[0]; + expected[i6 + 1] = rgb48Bytes[1]; + expected[i6 + 2] = rgb48Bytes[2]; + expected[i6 + 3] = rgb48Bytes[3]; + expected[i6 + 4] = rgb48Bytes[4]; + expected[i6 + 5] = rgb48Bytes[5]; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToRgb48Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromRgba64Bytes(int count) + { + byte[] source = CreateByteTestData(count * 8); + Span sourceSpan = source.AsSpan(); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i8 = i * 8; + expected[i].PackFromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromRgba64Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToRgba64Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 8]; + Rgba64 rgba = default; + + for (int i = 0; i < count; i++) + { + int i8 = i * 8; + source[i].ToRgba64(ref rgba); + Rgba64Bytes rgba64Bytes = Unsafe.As(ref rgba); + expected[i8] = rgba64Bytes[0]; + expected[i8 + 1] = rgba64Bytes[1]; + expected[i8 + 2] = rgba64Bytes[2]; + expected[i8 + 3] = rgba64Bytes[3]; + expected[i8 + 4] = rgba64Bytes[4]; + expected[i8 + 5] = rgba64Bytes[5]; + expected[i8 + 6] = rgba64Bytes[6]; + expected[i8 + 7] = rgba64Bytes[7]; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToRgba64Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromBgr24Bytes(int count) + { + byte[] source = CreateByteTestData(count * 3); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i3 = i * 3; + + expected[i].PackFromRgba32(new Rgba32(source[i3 + 2], source[i3 + 1], source[i3 + 0], 255)); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromBgr24Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToBgr24Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 3]; + var bgr = default(Bgr24); + + for (int i = 0; i < count; i++) + { + int i3 = i * 3; + source[i].ToBgr24(ref bgr); + expected[i3] = bgr.B; + expected[i3 + 1] = bgr.G; + expected[i3 + 2] = bgr.R; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToBgr24Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromBgra32Bytes(int count) + { + byte[] source = CreateByteTestData(count * 4); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + + expected[i].PackFromRgba32(new Rgba32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromBgra32Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToZyxwBytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 4]; + var bgra = default(Bgra32); + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + source[i].ToBgra32(ref bgra); + expected[i4] = bgra.B; + expected[i4 + 1] = bgra.G; + expected[i4 + 2] = bgra.R; + expected[i4 + 3] = bgra.A; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToBgra32Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromArgb32Bytes(int count) + { + byte[] source = CreateByteTestData(count * 4); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + + expected[i].PackFromRgba32(new Rgba32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromArgb32Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToArgb32Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 4]; + var argb = default(Argb32); + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + source[i].ToArgb32(ref argb); + expected[i4] = argb.A; + expected[i4 + 1] = argb.R; + expected[i4 + 2] = argb.G; + expected[i4 + 3] = argb.B; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToArgb32Bytes(s, d.GetSpan(), count) + ); + } + + private class TestBuffers : IDisposable + where TSource : struct + where TDest : struct + { + public TSource[] SourceBuffer { get; } + public IMemoryOwner ActualDestBuffer { get; } + public TDest[] ExpectedDestBuffer { get; } + + public TestBuffers(TSource[] source, TDest[] expectedDest) + { + this.SourceBuffer = source; + this.ExpectedDestBuffer = expectedDest; + this.ActualDestBuffer = Configuration.Default.MemoryAllocator.Allocate(expectedDest.Length); + } + + public void Dispose() + { + this.ActualDestBuffer.Dispose(); + } + + private const float Tolerance = 0.0001f; + + public void Verify() + { + int count = this.ExpectedDestBuffer.Length; + + if (typeof(TDest) == typeof(Vector4)) + { + + Span expected = MemoryMarshal.Cast(this.ExpectedDestBuffer.AsSpan()); + Span actual = MemoryMarshal.Cast(this.ActualDestBuffer.GetSpan()); + + for (int i = 0; i < count; i++) + { + // ReSharper disable PossibleNullReferenceException + Assert.Equal(expected[i], actual[i], new ApproximateFloatComparer(0.001f)); + // ReSharper restore PossibleNullReferenceException + } + } + else + { + Span expected = this.ExpectedDestBuffer.AsSpan(); + Span actual = this.ActualDestBuffer.GetSpan(); + for (int i = 0; i < count; i++) + { + Assert.Equal(expected[i], actual[i]); + } + } + } + } + + internal static void TestOperation( + TSource[] source, + TDest[] expected, + Action> action) + where TSource : struct + where TDest : struct + { + using (var buffers = new TestBuffers(source, expected)) + { + action(buffers.SourceBuffer, buffers.ActualDestBuffer); + buffers.Verify(); + } + } + + internal static Vector4[] CreateVector4TestData(int length) + { + var result = new Vector4[length]; + var rnd = new Random(42); // Deterministic random values + + for (int i = 0; i < result.Length; i++) + { + result[i] = GetVector(rnd); + } + return result; + } + + internal static TPixel[] CreatePixelTestData(int length) + { + var result = new TPixel[length]; + + var rnd = new Random(42); // Deterministic random values + + for (int i = 0; i < result.Length; i++) + { + Vector4 v = GetVector(rnd); + result[i].PackFromVector4(v); + } + + return result; + } + + internal static TPixel[] CreateScaledPixelTestData(int length) + { + var result = new TPixel[length]; + + var rnd = new Random(42); // Deterministic random values + + for (int i = 0; i < result.Length; i++) + { + Vector4 v = GetVector(rnd); + result[i].PackFromScaledVector4(v); + } + + return result; + } + + internal static byte[] CreateByteTestData(int length) + { + byte[] result = new byte[length]; + var rnd = new Random(42); // Deterministic random values + + for (int i = 0; i < result.Length; i++) + { + result[i] = (byte)rnd.Next(255); + } + return result; + } + + internal static Vector4 GetVector(Random rnd) + { + return new Vector4( + (float)rnd.NextDouble(), + (float)rnd.NextDouble(), + (float)rnd.NextDouble(), + (float)rnd.NextDouble() + ); + } + + [StructLayout(LayoutKind.Sequential)] + private unsafe struct Rgba64Bytes + { + public fixed byte Data[8]; + + 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 From af7d96d21462e6e080488f7d1933d1430834fadd Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 15 Oct 2018 01:11:59 +0200 Subject: [PATCH 145/381] SIMD byte -> float conversion: BulkConvertByteToNormalizedFloatFast --- src/ImageSharp/Common/Extensions/SimdUtils.cs | 45 +++++++++++++++++-- .../Color/Bulk/ToVector4.cs | 16 +++++-- .../ImageSharp.Benchmarks.csproj | 2 +- .../PixelFormats/PixelOperationsTests.cs | 24 ++++++++++ .../Tests/TestEnvironmentTests.cs | 2 + 5 files changed, 81 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Common/Extensions/SimdUtils.cs b/src/ImageSharp/Common/Extensions/SimdUtils.cs index db1e80dda2..56118a7644 100644 --- a/src/ImageSharp/Common/Extensions/SimdUtils.cs +++ b/src/ImageSharp/Common/Extensions/SimdUtils.cs @@ -105,13 +105,50 @@ namespace SixLabors.ImageSharp } } - internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + /// + /// Fast -> conversion for RyuJIT runtimes having dotnet/coreclr#10662 merged. + /// + /// https://github.com/dotnet/coreclr/pull/10662 + /// + /// + internal static void BulkConvertByteToNormalizedFloatFast(ReadOnlySpan source, Span dest) { - if (!Vector.IsHardwareAccelerated) + Guard.IsTrue( + source.Length % Vector.Count == 0, + nameof(source), + "dest.Length should be divisable by Vector.Count!"); + + int n = source.Length / Vector.Count; + + ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) { - throw new InvalidOperationException( - "Rgba32.PixelOperations.ToVector4SimdAligned() should not be called when Vector.IsHardwareAccelerated == false!"); + Vector b = Unsafe.Add(ref sourceBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + Vector f0 = Vector.ConvertToSingle(w0) * scale; + Vector f1 = Vector.ConvertToSingle(w1) * scale; + Vector f2 = Vector.ConvertToSingle(w2) * scale; + Vector f3 = Vector.ConvertToSingle(w3) * scale; + + ref Vector d = ref Unsafe.Add(ref destBase, i * 4); + d = f0; + Unsafe.Add(ref d, 1) = f1; + Unsafe.Add(ref d, 2) = f2; + Unsafe.Add(ref d, 3) = f3; } + } + + internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + { + GuardAvx2(nameof(BulkConvertByteToNormalizedFloat)); DebugGuard.IsTrue((dest.Length % Vector.Count) == 0, nameof(source), "dest.Length should be divisable by Vector.Count!"); diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 7b6f902d82..0e5e9d94f4 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Params( //64, - 1024)] + 2048)] public int Count { get; set; } [GlobalSetup] @@ -72,14 +72,14 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [CoreJob] - //[ClrJob] + [ClrJob] public class ToVector4_Rgba32 : ToVector4 { class Config : ManualConfig { } - [Benchmark] + //[Benchmark] public void BulkConvertByteToNormalizedFloat() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); @@ -87,5 +87,15 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk SimdUtils.BulkConvertByteToNormalizedFloat(sBytes, dFloats); } + + [Benchmark] + public void BulkConvertByteToNormalizedFloatFast() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.BulkConvertByteToNormalizedFloatFast(sBytes, dFloats); + } + } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 36b7d4db4b..e470e78212 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -1,6 +1,6 @@  - netcoreapp2.0;net461 + netcoreapp2.1;net461 Exe True SixLabors.ImageSharp.Benchmarks diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index a96da03e7f..2e84886c03 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -73,6 +73,30 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats ); } + [Fact] + public void BulkConvertByteToNormalizedFloatFast() + { + if (!Vector.IsHardwareAccelerated) + { + return; + } + + ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(128); + Vector4[] expected = CreateExpectedVector4Data(source); + + TestOperation( + source, + expected, + (s, d) => + { + ReadOnlySpan sBytes = MemoryMarshal.Cast(s); + Span dFloats = MemoryMarshal.Cast(d.Memory.Span); + + SimdUtils.BulkConvertByteToNormalizedFloatFast(sBytes, dFloats); + } + ); + } + // [Fact] // Profiling benchmark - enable manually! #pragma warning disable xUnit1013 // Public method should be marked as test diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs index 8a3e69059f..30bb16c2a0 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs @@ -3,6 +3,8 @@ using System; using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats; From 281c52786aff178f33ae5a928d4caff7b614a9ca Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 15 Oct 2018 01:30:35 +0200 Subject: [PATCH 146/381] move tests --- src/ImageSharp/Common/Extensions/SimdUtils.cs | 2 +- .../Color/Bulk/ToVector4.cs | 2 +- .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 40 ++++++++++++++++ .../PixelFormats/PixelOperationsTests.cs | 48 ------------------- .../TestUtilities/TestDataGenerator.cs | 7 +++ 5 files changed, 49 insertions(+), 50 deletions(-) diff --git a/src/ImageSharp/Common/Extensions/SimdUtils.cs b/src/ImageSharp/Common/Extensions/SimdUtils.cs index 56118a7644..481e0726df 100644 --- a/src/ImageSharp/Common/Extensions/SimdUtils.cs +++ b/src/ImageSharp/Common/Extensions/SimdUtils.cs @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp /// https://github.com/dotnet/coreclr/pull/10662 /// /// - internal static void BulkConvertByteToNormalizedFloatFast(ReadOnlySpan source, Span dest) + internal static void BulkConvertByteToNormalizedFloatWithExtendedIntrinsics(ReadOnlySpan source, Span dest) { Guard.IsTrue( source.Length % Vector.Count == 0, diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 0e5e9d94f4..3ea256e85a 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - SimdUtils.BulkConvertByteToNormalizedFloatFast(sBytes, dFloats); + SimdUtils.BulkConvertByteToNormalizedFloatWithExtendedIntrinsics(sBytes, dFloats); } } diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index c6c3b68f33..4e39af70fd 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -186,6 +186,46 @@ namespace SixLabors.ImageSharp.Tests.Common Assert.Equal(expected, dest); } + [Theory] + [InlineData(1, 0)] + [InlineData(2, 32)] + [InlineData(3, 128)] + public void BulkConvertByteToNormalizedFloat(int seed, int count) + { + if (this.SkipOnNonAvx2()) + { + return; + } + + byte[] source = new Random(seed).GenerateRandomByteArray(count); + float[] result = new float[count]; + float[] expected = source.Select(b => (float)b / 255f).ToArray(); + + SimdUtils.BulkConvertByteToNormalizedFloat(source, result); + + Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); + } + + [Theory] + [InlineData(1, 0)] + [InlineData(2, 32)] + [InlineData(3, 128)] + public void BulkConvertByteToNormalizedFloatWithExtendedIntrinsics(int seed, int count) + { + if (!Vector.IsHardwareAccelerated) + { + return; + } + + byte[] source = new Random(seed).GenerateRandomByteArray(count); + float[] result = new float[count]; + float[] expected = source.Select(b => (float)b / 255f).ToArray(); + + SimdUtils.BulkConvertByteToNormalizedFloatWithExtendedIntrinsics(source, result); + + Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); + } + [Theory] [InlineData(0)] [InlineData(7)] diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 2e84886c03..4d7ec71e72 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -49,54 +49,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats ); } - [Fact] - public void BulkConvertByteToNormalizedFloat() - { - if (!Vector.IsHardwareAccelerated) - { - return; - } - - ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(64); - Vector4[] expected = CreateExpectedVector4Data(source); - - TestOperation( - source, - expected, - (s, d) => - { - ReadOnlySpan sBytes = MemoryMarshal.Cast(s); - Span dFloats = MemoryMarshal.Cast(d.Memory.Span); - - SimdUtils.BulkConvertByteToNormalizedFloat(sBytes, dFloats); - } - ); - } - - [Fact] - public void BulkConvertByteToNormalizedFloatFast() - { - if (!Vector.IsHardwareAccelerated) - { - return; - } - - ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(128); - Vector4[] expected = CreateExpectedVector4Data(source); - - TestOperation( - source, - expected, - (s, d) => - { - ReadOnlySpan sBytes = MemoryMarshal.Cast(s); - Span dFloats = MemoryMarshal.Cast(d.Memory.Span); - - SimdUtils.BulkConvertByteToNormalizedFloatFast(sBytes, dFloats); - } - ); - } - // [Fact] // Profiling benchmark - enable manually! #pragma warning disable xUnit1013 // Public method should be marked as test diff --git a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs index 0b1b89cc00..6f3b18e1fc 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs @@ -46,6 +46,13 @@ namespace SixLabors.ImageSharp.Tests return values; } + public static byte[] GenerateRandomByteArray(this Random rnd, int length) + { + byte[] values = new byte[length]; + rnd.NextBytes(values); + return values; + } + private static float GetRandomFloat(Random rnd, float minVal, float maxVal) { return (float)rnd.NextDouble() * (maxVal - minVal) + minVal; From 3a455454f0f4aae90c074cc5310dab14acc8c3e5 Mon Sep 17 00:00:00 2001 From: j0rn Date: Mon, 15 Oct 2018 13:03:08 +0200 Subject: [PATCH 147/381] 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 56d351058feaee704ffd03b7cafd9380035849ce Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 15 Oct 2018 08:52:01 -0700 Subject: [PATCH 148/381] 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 f2f686c8881dcabb2235affd4759114329b3d1be Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 15 Oct 2018 08:54:58 -0700 Subject: [PATCH 149/381] 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 992010cbaa03a8f2d2d74c2d8bd0b1c47a602d5d Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 15 Oct 2018 09:22:27 -0700 Subject: [PATCH 150/381] 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 074a02634abab1e50c4152b0910e342d848a33a1 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 15 Oct 2018 09:25:11 -0700 Subject: [PATCH 151/381] 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 be93794ae24f732b8eec3b13409b09afe70efa93 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 15 Oct 2018 09:30:56 -0700 Subject: [PATCH 152/381] 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 b4d875336a6c1701bef7dec198437b864f7b2299 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 15 Oct 2018 10:10:35 -0700 Subject: [PATCH 153/381] 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 1c2aee03a633e89a017ba70120248264234174ff Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 15 Oct 2018 18:16:13 +0100 Subject: [PATCH 154/381] Generate bulk pixel operations for all standard packing operations and fix conversion --- src/ImageSharp/ImageFrame{TPixel}.cs | 14 +- src/ImageSharp/ImageSharp.csproj | 72 ++ src/ImageSharp/PixelFormats/Alpha8.cs | 8 + src/ImageSharp/PixelFormats/Argb32.cs | 31 +- src/ImageSharp/PixelFormats/Bgr24.cs | 17 +- src/ImageSharp/PixelFormats/Bgr565.cs | 8 + src/ImageSharp/PixelFormats/Bgra32.cs | 33 +- src/ImageSharp/PixelFormats/Bgra4444.cs | 8 + src/ImageSharp/PixelFormats/Bgra5551.cs | 11 +- src/ImageSharp/PixelFormats/Byte4.cs | 12 +- .../Argb32.PixelOperations.Generated.cs | 177 +++++ .../Argb32.PixelOperations.Generated.tt | 85 +++ .../Bgr24.PixelOperations.Generated.cs | 177 +++++ .../Bgr24.PixelOperations.Generated.tt | 85 +++ .../Bgra32.PixelOperations.Generated.cs | 177 +++++ .../Bgra32.PixelOperations.Generated.tt | 85 +++ .../Gray16.PixelOperations.Generated.cs | 177 +++++ .../Gray16.PixelOperations.Generated.tt | 85 +++ .../Gray8.PixelOperations.Generated.cs | 177 +++++ .../Gray8.PixelOperations.Generated.tt | 85 +++ .../PixelOperations{TPixel}.Generated.cs | 468 ++++++------ .../PixelOperations{TPixel}.Generated.tt | 70 +- .../Rgb24.PixelOperations.Generated.cs | 177 +++++ .../Rgb24.PixelOperations.Generated.tt | 85 +++ .../Rgb48.PixelOperations.Generated.cs | 177 +++++ .../Rgb48.PixelOperations.Generated.tt | 85 +++ .../Rgba32.PixelOperations.Generated.cs | 120 +-- .../Rgba32.PixelOperations.Generated.tt | 70 +- .../Rgba64.PixelOperations.Generated.cs | 177 +++++ .../Rgba64.PixelOperations.Generated.tt | 85 +++ src/ImageSharp/PixelFormats/Gray16.cs | 44 +- src/ImageSharp/PixelFormats/Gray8.cs | 34 +- src/ImageSharp/PixelFormats/HalfSingle.cs | 27 +- src/ImageSharp/PixelFormats/HalfVector2.cs | 8 + src/ImageSharp/PixelFormats/HalfVector4.cs | 8 + src/ImageSharp/PixelFormats/IPixel.cs | 12 + .../PixelFormats/NormalizedByte2.cs | 8 + .../PixelFormats/NormalizedByte4.cs | 8 + .../PixelFormats/NormalizedShort2.cs | 8 + .../PixelFormats/NormalizedShort4.cs | 8 + .../PixelFormats/PixelOperations{TPixel}.cs | 54 ++ src/ImageSharp/PixelFormats/Rg32.cs | 8 + src/ImageSharp/PixelFormats/Rgb24.cs | 19 +- src/ImageSharp/PixelFormats/Rgb48.cs | 22 +- src/ImageSharp/PixelFormats/Rgba1010102.cs | 14 +- .../PixelFormats/Rgba32.PixelOperations.cs | 66 +- src/ImageSharp/PixelFormats/Rgba32.cs | 16 + src/ImageSharp/PixelFormats/Rgba64.cs | 24 +- .../PixelFormats/RgbaVector.Definitions.cs | 721 ------------------ .../RgbaVector.PixelOperations.cs | 18 +- src/ImageSharp/PixelFormats/RgbaVector.cs | 10 +- src/ImageSharp/PixelFormats/Short2.cs | 12 +- src/ImageSharp/PixelFormats/Short4.cs | 12 +- .../PixelFormats/PixelOperationsTests.cs | 644 +++++++++++----- 54 files changed, 3441 insertions(+), 1402 deletions(-) create mode 100644 src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.cs create mode 100644 src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.tt create mode 100644 src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.cs create mode 100644 src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.tt create mode 100644 src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.cs create mode 100644 src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.tt create mode 100644 src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.cs create mode 100644 src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.tt create mode 100644 src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.cs create mode 100644 src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.tt create mode 100644 src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.cs create mode 100644 src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.tt create mode 100644 src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.cs create mode 100644 src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.tt create mode 100644 src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.cs create mode 100644 src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.tt delete mode 100644 src/ImageSharp/PixelFormats/RgbaVector.Definitions.cs diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index be1792ced1..ecf9e13ceb 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -2,8 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Buffers; -using System.Numerics; using System.Runtime.CompilerServices; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; @@ -289,22 +287,16 @@ namespace SixLabors.ImageSharp var target = new ImageFrame(configuration, this.Width, this.Height, this.MetaData.DeepClone()); - ParallelHelper.IterateRowsWithTempBuffer( + ParallelHelper.IterateRows( this.Bounds(), configuration, - (rows, tempRowBuffer) => + (rows) => { 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); + PixelOperations.Instance.To(sourceRow, targetRow, sourceRow.Length); } }); diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index a7ca0a014c..7eec03cb6a 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -76,10 +76,42 @@ TextTemplatingFileGenerator PixelOperations{TPixel}.Generated.cs + + TextTemplatingFileGenerator + Argb32.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Bgr24.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Bgra32.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Gray8.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Gray16.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Rgb24.PixelOperations.Generated.cs + TextTemplatingFileGenerator Rgba32.PixelOperations.Generated.cs + + TextTemplatingFileGenerator + Rgb48.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Rgba64.PixelOperations.Generated.cs + PorterDuffFunctions.Generated.cs TextTemplatingFileGenerator @@ -110,11 +142,51 @@ True PixelOperations{TPixel}.Generated.tt + + True + True + Argb32.PixelOperations.Generated.tt + + + True + True + Bgr24.PixelOperations.Generated.tt + + + True + True + Bgra32.PixelOperations.Generated.tt + + + True + True + Gray8.PixelOperations.Generated.tt + + + True + True + Gray16.PixelOperations.Generated.tt + + + True + True + Rgb24.PixelOperations.Generated.tt + True True Rgba32.PixelOperations.Generated.tt + + True + True + Rgb48.PixelOperations.Generated.tt + + + True + True + Rgba64.PixelOperations.Generated.tt + True True diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/Alpha8.cs index 063200c69e..1e724768d0 100644 --- a/src/ImageSharp/PixelFormats/Alpha8.cs +++ b/src/ImageSharp/PixelFormats/Alpha8.cs @@ -79,6 +79,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackedValue = source.A; + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackedValue = byte.MaxValue; + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackedValue = source.A; @@ -91,6 +95,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackedValue = byte.MaxValue; + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackedValue = byte.MaxValue; + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackedValue = source.A; diff --git a/src/ImageSharp/PixelFormats/Argb32.cs b/src/ImageSharp/PixelFormats/Argb32.cs index 0da8516a3e..1e3bd93262 100644 --- a/src/ImageSharp/PixelFormats/Argb32.cs +++ b/src/ImageSharp/PixelFormats/Argb32.cs @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// as it avoids the need to create new values for modification operations. /// [StructLayout(LayoutKind.Sequential)] - public struct Argb32 : IPixel, IPackedVector + public partial struct Argb32 : IPixel, IPackedVector { /// /// Gets or sets the alpha component. @@ -165,7 +165,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static bool operator !=(Argb32 left, Argb32 right) => !left.Equals(right); /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -187,6 +187,16 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackedValue = source.PackedValue; + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = byte.MaxValue; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) @@ -218,6 +228,16 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = byte.MaxValue; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = byte.MaxValue; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) @@ -269,13 +289,6 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.Argb.GetHashCode(); - /// - /// Gets the representation without normalizing to [0, 1] - /// - /// A of values in [0, 255] - [MethodImpl(InliningOptions.ShortMethod)] - internal Vector4 ToByteScaledVector4() => new Vector4(this.R, this.G, this.B, this.A); - /// /// Packs the four floats into a color. /// diff --git a/src/ImageSharp/PixelFormats/Bgr24.cs b/src/ImageSharp/PixelFormats/Bgr24.cs index 063fed5221..ed65bebf7f 100644 --- a/src/ImageSharp/PixelFormats/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/Bgr24.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// [StructLayout(LayoutKind.Explicit)] - public struct Bgr24 : IPixel + public partial struct Bgr24 : IPixel { /// /// The blue component. @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static bool operator !=(Bgr24 left, Bgr24 right) => !left.Equals(right); /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -104,6 +104,10 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = source.B; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this = source; + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) @@ -132,6 +136,15 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = rgb; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this = source.Bgr; diff --git a/src/ImageSharp/PixelFormats/Bgr565.cs b/src/ImageSharp/PixelFormats/Bgr565.cs index 5b19fb25c1..454f458b12 100644 --- a/src/ImageSharp/PixelFormats/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/Bgr565.cs @@ -87,6 +87,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromVector4(source.ToVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromVector4(source.ToVector4()); @@ -99,6 +103,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromVector4(source.ToVector4()); diff --git a/src/ImageSharp/PixelFormats/Bgra32.cs b/src/ImageSharp/PixelFormats/Bgra32.cs index 6fd0867797..9b0ed4f96d 100644 --- a/src/ImageSharp/PixelFormats/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/Bgra32.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// [StructLayout(LayoutKind.Sequential)] - public struct Bgra32 : IPixel, IPackedVector + public partial struct Bgra32 : IPixel, IPackedVector { /// /// Gets or sets the blue component. @@ -121,7 +121,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static bool operator !=(Bgra32 left, Bgra32 right) => !left.Equals(right); /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -151,7 +151,17 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackedValue = source.PackedValue; + public void PackFromBgr24(Bgr24 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = byte.MaxValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this = source; /// [MethodImpl(InliningOptions.ShortMethod)] @@ -184,6 +194,16 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = source.A; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = byte.MaxValue; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A); @@ -220,13 +240,6 @@ namespace SixLabors.ImageSharp.PixelFormats /// public override string ToString() => $"Bgra32({this.B}, {this.G}, {this.R}, {this.A})"; - /// - /// Gets the representation without normalizing to [0, 1] - /// - /// A of values in [0, 255] - [MethodImpl(InliningOptions.ShortMethod)] - internal Vector4 ToByteScaledVector4() => new Vector4(this.R, this.G, this.B, this.A); - /// /// Packs a into a color. /// diff --git a/src/ImageSharp/PixelFormats/Bgra4444.cs b/src/ImageSharp/PixelFormats/Bgra4444.cs index 8a5e3f76b3..08484eba8d 100644 --- a/src/ImageSharp/PixelFormats/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/Bgra4444.cs @@ -90,6 +90,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -102,6 +106,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Bgra5551.cs b/src/ImageSharp/PixelFormats/Bgra5551.cs index 25f289b846..df0a467301 100644 --- a/src/ImageSharp/PixelFormats/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/Bgra5551.cs @@ -91,6 +91,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -103,6 +107,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -147,8 +155,5 @@ namespace SixLabors.ImageSharp.PixelFormats | (((int)Math.Round(vector.Z * 31F) & 0x1F) << 0) | (((int)Math.Round(vector.W) & 0x1) << 15)); } - - [MethodImpl(InliningOptions.ShortMethod)] - private Vector4 ToByteScaledVector4() => this.ToVector4() * 255F; } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Byte4.cs b/src/ImageSharp/PixelFormats/Byte4.cs index fbdf4862db..34546e0271 100644 --- a/src/ImageSharp/PixelFormats/Byte4.cs +++ b/src/ImageSharp/PixelFormats/Byte4.cs @@ -89,11 +89,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromVector4(source.ToByteScaledVector4()); + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromVector4(source.ToByteScaledVector4()); + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -103,6 +107,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.cs new file mode 100644 index 0000000000..0b40df8dae --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Argb32 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.tt new file mode 100644 index 0000000000..f35adee022 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Argb32 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgb48"); + GenerateConvertToMethod("Rgba64"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.cs new file mode 100644 index 0000000000..e895254576 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Bgr24 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.tt new file mode 100644 index 0000000000..76163549b0 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Bgr24 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgb48"); + GenerateConvertToMethod("Rgba64"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.cs new file mode 100644 index 0000000000..2311e0bde6 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Bgra32 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.tt new file mode 100644 index 0000000000..4c2925d18f --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Bgra32 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgb48"); + GenerateConvertToMethod("Rgba64"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.cs new file mode 100644 index 0000000000..a2d9aa755f --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Gray16 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromGray16(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.tt new file mode 100644 index 0000000000..b900e343a7 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Gray16 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromGray16(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgb48"); + GenerateConvertToMethod("Rgba64"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.cs new file mode 100644 index 0000000000..de2c11d4d9 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Gray8 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromGray8(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.tt new file mode 100644 index 0000000000..4590420e57 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Gray8 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromGray8(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgb48"); + GenerateConvertToMethod("Rgba64"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs index 852ff73e0e..66966543fc 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs @@ -11,633 +11,633 @@ namespace SixLabors.ImageSharp.PixelFormats public partial class PixelOperations { /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromRgba64(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - 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; + ref Argb32 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba64(temp); + ref Argb32 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromArgb32(sp); } } /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// 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 PackFromRgba64Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromArgb32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromRgba64(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromArgb32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } + /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToRgba64(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Argb32 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destBaseRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destBaseRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgba64Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + internal void ToArgb32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgba64(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToArgb32(sourcePixels, MemoryMarshal.Cast(destBytes), count); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromRgb48(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - 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; + ref Bgr24 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgb48(temp); + ref Bgr24 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromBgr24(sp); } } /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// 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 PackFromRgb48Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromBgr24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromRgb48(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromBgr24(MemoryMarshal.Cast(sourceBytes), destPixels, count); } + /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToRgb48(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Bgr24 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destBaseRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgb48Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + internal void ToBgr24Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgb48(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToBgr24(sourcePixels, MemoryMarshal.Cast(destBytes), count); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - 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; + ref Bgra32 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba32(temp); + ref Bgra32 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromBgra32(sp); } } /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// 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 PackFromRgba32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromBgra32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromRgba32(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromBgra32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } + /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToRgba32(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Bgra32 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgba32Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + internal void ToBgra32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgba32(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToBgra32(sourcePixels, MemoryMarshal.Cast(destBytes), count); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromGray8(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - 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; + ref Gray8 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromBgra32(temp); + ref Gray8 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromGray8(sp); } } /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// 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 PackFromBgra32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromGray8Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromBgra32(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromGray8(MemoryMarshal.Cast(sourceBytes), destPixels, count); } + /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToBgra32(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Gray8 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destBaseRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToBgra32Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + internal void ToGray8Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToBgra32(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToGray8(sourcePixels, MemoryMarshal.Cast(destBytes), count); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromGray16(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - 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; + ref Gray16 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp.Rgb = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba32(temp); + ref Gray16 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromGray16(sp); } } /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// 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 PackFromRgb24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromGray16Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromRgb24(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromGray16(MemoryMarshal.Cast(sourceBytes), destPixels, count); } + /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToRgb24(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Gray16 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destBaseRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destBaseRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgb24Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + internal void ToGray16Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgb24(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToGray16(sourcePixels, MemoryMarshal.Cast(destBytes), count); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - 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; + ref Rgb24 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp.Bgr = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba32(temp); + ref Rgb24 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromRgb24(sp); } } /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// 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 PackFromBgr24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromRgb24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromBgr24(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromRgb24(MemoryMarshal.Cast(sourceBytes), destPixels, count); } + /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToBgr24(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Rgb24 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destBaseRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToBgr24Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + internal void ToRgb24Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToBgr24(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToRgb24(sourcePixels, MemoryMarshal.Cast(destBytes), count); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - 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; + ref Rgba32 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromArgb32(temp); + ref Rgba32 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromRgba32(sp); } } /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// 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 PackFromArgb32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromRgba32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromArgb32(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromRgba32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } + /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToArgb32(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Rgba32 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destBaseRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToArgb32Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + internal void ToRgba32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToArgb32(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToRgba32(sourcePixels, MemoryMarshal.Cast(destBytes), count); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromGray8(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromRgb48(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - ref Gray8 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; + ref Rgb48 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromGray8(temp); + ref Rgb48 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromRgb48(sp); } } /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// 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 PackFromGray8Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromRgb48Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromGray8(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromRgb48(MemoryMarshal.Cast(sourceBytes), destPixels, count); } + /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToGray8(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Gray8 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Rgb48 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Gray8 dp = ref Unsafe.Add(ref destBaseRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destBaseRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToGray8Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + internal void ToRgb48Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToGray8(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToRgb48(sourcePixels, MemoryMarshal.Cast(destBytes), count); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromGray16(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromRgba64(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - ref Gray16 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; + ref Rgba64 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromGray16(temp); + ref Rgba64 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromRgba64(sp); } } /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// 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 PackFromGray16Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromRgba64Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromGray16(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromRgba64(MemoryMarshal.Cast(sourceBytes), destPixels, count); } + /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToGray16(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Gray16 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Rgba64 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Gray16 dp = ref Unsafe.Add(ref destBaseRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destBaseRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToGray16Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + internal void ToRgba64Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToGray16(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToRgba64(sourcePixels, MemoryMarshal.Cast(destBytes), count); } } } \ 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 9fbe57ed9b..913dabb087 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt @@ -11,7 +11,7 @@ <#@ output extension=".cs" #> <# - void GeneratePackFromMethods(string pixelType, string tempPixelType, string assignToTempCode) + void GeneratePackFromMethods(string pixelType) { #> @@ -25,17 +25,15 @@ { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - 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; + ref <#=pixelType#> sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - <#=assignToTempCode#> - dp.PackFrom<#=tempPixelType#>(temp); + ref <#=pixelType#> sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFrom<#=pixelType#>(sp); } } @@ -51,6 +49,7 @@ { this.PackFrom<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); } + <# } @@ -61,19 +60,20 @@ /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> dest, int count) + internal virtual void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destBaseRef = ref MemoryMarshal.GetReference(dest); + ref <#=pixelType#> destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destBaseRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } @@ -82,13 +82,13 @@ /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void To<#=pixelType#>Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + internal void To<#=pixelType#>Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.To<#=pixelType#>(sourceColors, MemoryMarshal.Cast>(destBytes), count); + this.To<#=pixelType#>(sourcePixels, MemoryMarshal.Cast>(destBytes), count); } <# } @@ -107,32 +107,32 @@ namespace SixLabors.ImageSharp.PixelFormats public partial class PixelOperations {<# - GeneratePackFromMethods("Rgba64", "Rgba64", "temp = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Rgba64"); - - GeneratePackFromMethods("Rgb48", "Rgb48", "temp = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Rgb48"); - - GeneratePackFromMethods("Rgba32", "Rgba32", "temp = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Rgba32"); - - GeneratePackFromMethods("Bgra32", "Bgra32", "temp = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Bgra32"); - - GeneratePackFromMethods("Rgb24", "Rgba32", "temp.Rgb = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Rgb24"); + GeneratePackFromMethods("Argb32"); + GenerateToDestFormatMethods("Argb32"); - GeneratePackFromMethods("Bgr24", "Rgba32", "temp.Bgr = Unsafe.Add(ref sourceRef, i);"); + GeneratePackFromMethods("Bgr24"); GenerateToDestFormatMethods("Bgr24"); - GeneratePackFromMethods("Argb32", "Argb32", "temp = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Argb32"); + GeneratePackFromMethods("Bgra32"); + GenerateToDestFormatMethods("Bgra32"); - GeneratePackFromMethods("Gray8", "Gray8", "temp = Unsafe.Add(ref sourceRef, i);"); + GeneratePackFromMethods("Gray8"); GenerateToDestFormatMethods("Gray8"); - GeneratePackFromMethods("Gray16", "Gray16", "temp = Unsafe.Add(ref sourceRef, i);"); + GeneratePackFromMethods("Gray16"); GenerateToDestFormatMethods("Gray16"); + GeneratePackFromMethods("Rgb24"); + GenerateToDestFormatMethods("Rgb24"); + + GeneratePackFromMethods("Rgba32"); + GenerateToDestFormatMethods("Rgba32"); + + GeneratePackFromMethods("Rgb48"); + GenerateToDestFormatMethods("Rgb48"); + + GeneratePackFromMethods("Rgba64"); + GenerateToDestFormatMethods("Rgba64"); + #> } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.cs new file mode 100644 index 0000000000..ad4ee2764e --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgb24 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.tt new file mode 100644 index 0000000000..6a10b401f4 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgb24 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgb48"); + GenerateConvertToMethod("Rgba64"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.cs new file mode 100644 index 0000000000..0a1ef03873 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgb48 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromRgb48(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.tt new file mode 100644 index 0000000000..e38c85bf62 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgb48 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromRgb48(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgba64"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs index 9621505952..bd3e014b4d 100644 --- a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs @@ -13,133 +13,161 @@ namespace SixLabors.ImageSharp.PixelFormats /// public partial struct Rgba32 { + + /// + /// Provides optimized overrides for bulk operations. + /// internal partial class PixelOperations { + /// + internal override void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + /// - internal override void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - Unsafe.As(ref dp) = sp; dp.A = byte.MaxValue; + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba32(sp); } } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span dest, int count) + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destRef = ref MemoryMarshal.GetReference(dest); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - dp = Unsafe.As(ref sp); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba32(sp); } } /// - internal override void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.Bgr = sp; dp.A = byte.MaxValue; + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba32(sp); } } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span dest, int count) + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(dest); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.Bgr; + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba32(sp); } } /// - internal override void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.R = sp.R; dp.G = sp.G; dp.B = sp.B; dp.A = sp.A; + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba32(sp); } } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span dest, int count) + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(dest); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + dp.PackFromRgba32(sp); } } /// - internal override void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.R = sp.R; dp.G = sp.G; dp.B = sp.B; dp.A = sp.A; + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba32(sp); } } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span dest, int count) + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(dest); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + dp.PackFromRgba32(sp); } } diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt index 9d9145f0b9..23d0be740e 100644 --- a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt @@ -9,45 +9,24 @@ <#@ import namespace="System.Collections.Generic" #> <#@ output extension=".cs" #> <# - void GeneratePackFromMethod(string pixelType, string converterCode) + void GenerateConvertToMethod(string pixelType) { #> /// - internal override void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - - for (int i = 0; i < count; i++) - { - ref <#=pixelType#> sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - <#=converterCode#> - } - } - <# - } - - void GenerateConvertToMethod(string pixelType, string converterCode) - { - #> - - /// - internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> dest, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(dest); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - <#=converterCode#> + + dp.PackFromRgba32(sp); } } <# @@ -68,20 +47,37 @@ namespace SixLabors.ImageSharp.PixelFormats /// public partial struct Rgba32 { + + /// + /// Provides optimized overrides for bulk operations. + /// internal partial class PixelOperations { - <# - GeneratePackFromMethod("Rgb24", "Unsafe.As(ref dp) = sp; dp.A = byte.MaxValue;"); - GenerateConvertToMethod("Rgb24", "dp = Unsafe.As(ref sp);"); + /// + internal override void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - GeneratePackFromMethod("Bgr24", "dp.Bgr = sp; dp.A = byte.MaxValue;"); - GenerateConvertToMethod("Bgr24", "dp = sp.Bgr;"); - - GeneratePackFromMethod("Bgra32", "dp.R = sp.R; dp.G = sp.G; dp.B = sp.B; dp.A = sp.A;"); - GenerateConvertToMethod("Bgra32", "dp.PackFromRgba32(sp);"); + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - GeneratePackFromMethod("Argb32", "dp.R = sp.R; dp.G = sp.G; dp.B = sp.B; dp.A = sp.A;"); - GenerateConvertToMethod("Argb32", "dp.PackFromRgba32(sp);"); + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgb48"); + GenerateConvertToMethod("Rgba64"); #> } diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.cs new file mode 100644 index 0000000000..e6f9b37a70 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgba64 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromRgba64(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.tt new file mode 100644 index 0000000000..e998341570 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgba64 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromRgba64(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgb48"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Gray16.cs b/src/ImageSharp/PixelFormats/Gray16.cs index f9aada9374..34f221d79c 100644 --- a/src/ImageSharp/PixelFormats/Gray16.cs +++ b/src/ImageSharp/PixelFormats/Gray16.cs @@ -13,9 +13,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. /// /// - public struct Gray16 : IPixel, IPackedVector + public partial struct Gray16 : IPixel, IPackedVector { private const float Max = ushort.MaxValue; + private const float Average = 1 / 3F; /// /// Initializes a new instance of the struct. @@ -49,7 +50,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static bool operator !=(Gray16 left, Gray16 right) => !left.Equals(right); /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -63,11 +64,8 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; - this.PackedValue = ImageMaths.Get16BitBT709Luminance( - (ushort)MathF.Round(vector.X), - (ushort)MathF.Round(vector.Y), - (ushort)MathF.Round(vector.Z)); + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max * Average; + this.PackedValue = (ushort)MathF.Round(vector.X + vector.Y + vector.Z); } /// @@ -88,6 +86,16 @@ namespace SixLabors.ImageSharp.PixelFormats ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) + { + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) @@ -106,6 +114,16 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackedValue = source.PackedValue; + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) + { + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) @@ -130,7 +148,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B); + public void PackFromRgba64(Rgba64 source) => this.PackedValue = ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B); /// public override bool Equals(object obj) => obj is Gray16 other && this.Equals(other); @@ -145,5 +163,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); + + [MethodImpl(InliningOptions.ShortMethod)] + internal void ConvertFromRgbaScaledVector4(Vector4 vector) + { + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + (ushort)MathF.Round(vector.X), + (ushort)MathF.Round(vector.Y), + (ushort)MathF.Round(vector.Z)); + } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Gray8.cs b/src/ImageSharp/PixelFormats/Gray8.cs index b1fa2b1e14..5812405876 100644 --- a/src/ImageSharp/PixelFormats/Gray8.cs +++ b/src/ImageSharp/PixelFormats/Gray8.cs @@ -12,17 +12,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. /// /// - public struct Gray8 : IPixel, IPackedVector + public partial struct Gray8 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// private static readonly Vector4 MaxBytes = new Vector4(255F); - - /// - /// The half vector value. - /// private static readonly Vector4 Half = new Vector4(0.5F); + private const float Average = 1 / 3F; /// /// Initializes a new instance of the struct. @@ -56,7 +50,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static bool operator !=(Gray8 left, Gray8 right) => !left.Equals(right); /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -72,9 +66,8 @@ namespace SixLabors.ImageSharp.PixelFormats { vector *= MaxBytes; vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - this.PackedValue = ImageMaths.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z); + vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes) * Average; + this.PackedValue = (byte)(vector.X + vector.Y + vector.Z); } /// @@ -89,6 +82,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); @@ -101,6 +98,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackedValue = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); @@ -138,5 +139,14 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); + + [MethodImpl(InliningOptions.ShortMethod)] + internal void ConvertFromRgbaScaledVector4(Vector4 vector) + { + vector *= MaxBytes; + vector += Half; + vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + this.PackedValue = ImageMaths.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z); + } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/HalfSingle.cs b/src/ImageSharp/PixelFormats/HalfSingle.cs index 8048a3825d..78edc9a08e 100644 --- a/src/ImageSharp/PixelFormats/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/HalfSingle.cs @@ -14,16 +14,6 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct HalfSingle : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half vector value. - /// - private static readonly Vector4 Half = new Vector4(0.5F); - /// /// Initializes a new instance of the struct. /// @@ -89,6 +79,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -101,6 +95,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -137,14 +135,5 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - - [MethodImpl(InliningOptions.ShortMethod)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - return Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/HalfVector2.cs b/src/ImageSharp/PixelFormats/HalfVector2.cs index f398f508ba..e3777bc2fb 100644 --- a/src/ImageSharp/PixelFormats/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/HalfVector2.cs @@ -90,6 +90,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -102,6 +106,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/HalfVector4.cs b/src/ImageSharp/PixelFormats/HalfVector4.cs index 45d93efc09..079c3ee383 100644 --- a/src/ImageSharp/PixelFormats/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/HalfVector4.cs @@ -98,6 +98,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -110,6 +114,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index a3017501ce..87125fa0a3 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -61,6 +61,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// The value. void PackFromArgb32(Argb32 source); + /// + /// Packs the pixel from an value. + /// + /// The value. + void PackFromBgr24(Bgr24 source); + /// /// Packs the pixel from an value. /// @@ -79,6 +85,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// The value. void PackFromGray16(Gray16 source); + /// + /// Packs the pixel from an value. + /// + /// The value. + void PackFromRgb24(Rgb24 source); + /// /// Packs the pixel from an value. /// diff --git a/src/ImageSharp/PixelFormats/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/NormalizedByte2.cs index 86b5280902..3eaa69c03e 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte2.cs @@ -97,6 +97,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -113,6 +117,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/NormalizedByte4.cs index b538e4a449..e0e3e65020 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte4.cs @@ -102,6 +102,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -114,6 +118,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/NormalizedShort2.cs index 6135826f48..0aa5736379 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort2.cs @@ -97,6 +97,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -109,6 +113,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/NormalizedShort4.cs index 9717829a24..577e901544 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort4.cs @@ -104,6 +104,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -116,6 +120,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index b12a2bfa58..f1b40e81f0 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -105,6 +105,60 @@ namespace SixLabors.ImageSharp.PixelFormats } } + /// + /// Performs a bulk conversion of a collection of one pixel format into another. + /// + /// The pixel format. + /// The to the source colors. + /// The to the destination colors. + /// The number of pixels to convert. + internal virtual void To(ReadOnlySpan sourceColors, Span destinationColors, int count) + where TPixel2 : struct, IPixel + { + GuardSpans(sourceColors, nameof(sourceColors), destinationColors, nameof(destinationColors), count); + + ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); + + // Gray8 and Gray16 are special implementations of IPixel in that they do not conform to the + // standard RGBA colorspace format and must be converted from RGBA using the special ITU BT709 alogrithm. + // One of the requirements of PackFromScaledVector4/ToScaledVector4 is that it unaware of this and + // packs/unpacks the pixel without and conversion so we employ custom methods do do this. + if (typeof(TPixel2).Equals(typeof(Gray16))) + { + ref Gray16 gray16Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(destinationColors)); + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref gray16Ref, i); + dp.ConvertFromRgbaScaledVector4(sp.ToScaledVector4()); + } + + return; + } + + if (typeof(TPixel2).Equals(typeof(Gray8))) + { + ref Gray8 gray8Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(destinationColors)); + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref gray8Ref, i); + dp.ConvertFromRgbaScaledVector4(sp.ToScaledVector4()); + } + + return; + } + + // Normal converson + ref TPixel2 destRef = ref MemoryMarshal.GetReference(destinationColors); + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref TPixel2 dp = ref Unsafe.Add(ref destRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); + } + } + /// /// Verifies that the given 'source' and 'destination' spans are at least of 'minLength' size. /// Throwing an if the condition is not met. diff --git a/src/ImageSharp/PixelFormats/Rg32.cs b/src/ImageSharp/PixelFormats/Rg32.cs index 3375a9753b..02c294b4ff 100644 --- a/src/ImageSharp/PixelFormats/Rg32.cs +++ b/src/ImageSharp/PixelFormats/Rg32.cs @@ -85,6 +85,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -97,6 +101,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Rgb24.cs b/src/ImageSharp/PixelFormats/Rgb24.cs index ae037b3764..a2b896605d 100644 --- a/src/ImageSharp/PixelFormats/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/Rgb24.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// [StructLayout(LayoutKind.Explicit)] - public struct Rgb24 : IPixel + public partial struct Rgb24 : IPixel { /// /// The red component. @@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static bool operator !=(Rgb24 left, Rgb24 right) => !left.Equals(right); /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -118,6 +118,15 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = source.B; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) @@ -148,7 +157,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this = Unsafe.As(ref source); + public void PackFromRgb24(Rgb24 source) => this = source; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this = source.Rgb; /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Rgb48.cs b/src/ImageSharp/PixelFormats/Rgb48.cs index 2ee1be6fe4..7406fda429 100644 --- a/src/ImageSharp/PixelFormats/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/Rgb48.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// [StructLayout(LayoutKind.Sequential)] - public struct Rgb48 : IPixel + public partial struct Rgb48 : IPixel { private const float Max = ushort.MaxValue; @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static bool operator !=(Rgb48 left, Rgb48 right) => !left.Equals(right); /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -104,6 +104,15 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) + { + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) @@ -136,6 +145,15 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = source.PackedValue; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) + { + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) diff --git a/src/ImageSharp/PixelFormats/Rgba1010102.cs b/src/ImageSharp/PixelFormats/Rgba1010102.cs index 8bcf34f309..86b639e229 100644 --- a/src/ImageSharp/PixelFormats/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/Rgba1010102.cs @@ -91,6 +91,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -105,16 +109,20 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// + /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs index 40d8e0190d..3111a6ee15 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs @@ -86,33 +86,10 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) - { - Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); - Guard.MustBeSizedAtLeast(destinationVectors, count, nameof(destinationVectors)); - - if (count < 256 || !Vector.IsHardwareAccelerated) - { - // Doesn't worth to bother with SIMD: - base.ToVector4(sourceColors, destinationVectors, count); - return; - } - - int remainder = count % Vector.Count; - int alignedCount = count - remainder; - - if (alignedCount > 0) - { - ToVector4SimdAligned(sourceColors, destinationVectors, alignedCount); - } + internal override void PackFromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) => this.PackFromVector4(sourceVectors, destinationColors, count); - if (remainder > 0) - { - sourceColors = sourceColors.Slice(alignedCount); - destinationVectors = destinationVectors.Slice(alignedCount); - base.ToVector4(sourceColors, destinationVectors, remainder); - } - } + /// + internal override void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) => this.ToVector4(sourceColors, destinationVectors, count); /// internal override void PackFromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) @@ -145,25 +122,32 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) => this.ToVector4(sourceColors, destinationVectors, count); - - /// - internal override void PackFromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) => this.PackFromVector4(sourceVectors, destinationColors, count); - - /// - internal override void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) + internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); + Guard.MustBeSizedAtLeast(destinationVectors, count, nameof(destinationVectors)); - source.Slice(0, count).CopyTo(destPixels); - } + if (count < 256 || !Vector.IsHardwareAccelerated) + { + // Doesn't worth to bother with SIMD: + base.ToVector4(sourceColors, destinationVectors, count); + return; + } - /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span dest, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + int remainder = count % Vector.Count; + int alignedCount = count - remainder; - sourcePixels.Slice(0, count).CopyTo(dest); + if (alignedCount > 0) + { + ToVector4SimdAligned(sourceColors, destinationVectors, alignedCount); + } + + if (remainder > 0) + { + sourceColors = sourceColors.Slice(alignedCount); + destinationVectors = destinationVectors.Slice(alignedCount); + base.ToVector4(sourceColors, destinationVectors, remainder); + } } /// diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index 83620c823c..e7814d23ac 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -246,6 +246,14 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = source.A; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) + { + this.Bgr = source; + this.A = byte.MaxValue; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) @@ -277,6 +285,14 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = byte.MaxValue; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) + { + this.Rgb = source; + this.A = byte.MaxValue; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this = source; diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/Rgba64.cs index 623f7051af..738c5e3dd8 100644 --- a/src/ImageSharp/PixelFormats/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/Rgba64.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// [StructLayout(LayoutKind.Sequential)] - public struct Rgba64 : IPixel, IPackedVector + public partial struct Rgba64 : IPixel, IPackedVector { private const float Max = ushort.MaxValue; @@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static bool operator !=(Rgba64 left, Rgba64 right) => left.PackedValue != right.PackedValue; /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -134,6 +134,16 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A); } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) + { + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + this.A = ushort.MaxValue; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) @@ -165,6 +175,16 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = ushort.MaxValue; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) + { + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + this.A = ushort.MaxValue; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) diff --git a/src/ImageSharp/PixelFormats/RgbaVector.Definitions.cs b/src/ImageSharp/PixelFormats/RgbaVector.Definitions.cs deleted file mode 100644 index 2ef37c43ae..0000000000 --- a/src/ImageSharp/PixelFormats/RgbaVector.Definitions.cs +++ /dev/null @@ -1,721 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Provides operators and composition algorithms. - /// - public partial struct RgbaVector - { - /// - /// Represents a matching the W3C definition that has an hex value of #F0F8FF. - /// - public static readonly RgbaVector AliceBlue = NamedColors.AliceBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #FAEBD7. - /// - public static readonly RgbaVector AntiqueWhite = NamedColors.AntiqueWhite; - - /// - /// Represents a matching the W3C definition that has an hex value of #00FFFF. - /// - public static readonly RgbaVector Aqua = NamedColors.Aqua; - - /// - /// Represents a matching the W3C definition that has an hex value of #7FFFD4. - /// - public static readonly RgbaVector Aquamarine = NamedColors.Aquamarine; - - /// - /// Represents a matching the W3C definition that has an hex value of #F0FFFF. - /// - public static readonly RgbaVector Azure = NamedColors.Azure; - - /// - /// Represents a matching the W3C definition that has an hex value of #F5F5DC. - /// - public static readonly RgbaVector Beige = NamedColors.Beige; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFE4C4. - /// - public static readonly RgbaVector Bisque = NamedColors.Bisque; - - /// - /// Represents a matching the W3C definition that has an hex value of #000000. - /// - public static readonly RgbaVector Black = NamedColors.Black; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFEBCD. - /// - public static readonly RgbaVector BlanchedAlmond = NamedColors.BlanchedAlmond; - - /// - /// Represents a matching the W3C definition that has an hex value of #0000FF. - /// - public static readonly RgbaVector Blue = NamedColors.Blue; - - /// - /// Represents a matching the W3C definition that has an hex value of #8A2BE2. - /// - public static readonly RgbaVector BlueViolet = NamedColors.BlueViolet; - - /// - /// Represents a matching the W3C definition that has an hex value of #A52A2A. - /// - public static readonly RgbaVector Brown = NamedColors.Brown; - - /// - /// Represents a matching the W3C definition that has an hex value of #DEB887. - /// - public static readonly RgbaVector BurlyWood = NamedColors.BurlyWood; - - /// - /// Represents a matching the W3C definition that has an hex value of #5F9EA0. - /// - public static readonly RgbaVector CadetBlue = NamedColors.CadetBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #7FFF00. - /// - public static readonly RgbaVector Chartreuse = NamedColors.Chartreuse; - - /// - /// Represents a matching the W3C definition that has an hex value of #D2691E. - /// - public static readonly RgbaVector Chocolate = NamedColors.Chocolate; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF7F50. - /// - public static readonly RgbaVector Coral = NamedColors.Coral; - - /// - /// Represents a matching the W3C definition that has an hex value of #6495ED. - /// - public static readonly RgbaVector CornflowerBlue = NamedColors.CornflowerBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFF8DC. - /// - public static readonly RgbaVector Cornsilk = NamedColors.Cornsilk; - - /// - /// Represents a matching the W3C definition that has an hex value of #DC143C. - /// - public static readonly RgbaVector Crimson = NamedColors.Crimson; - - /// - /// Represents a matching the W3C definition that has an hex value of #00FFFF. - /// - public static readonly RgbaVector Cyan = NamedColors.Cyan; - - /// - /// Represents a matching the W3C definition that has an hex value of #00008B. - /// - public static readonly RgbaVector DarkBlue = NamedColors.DarkBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #008B8B. - /// - public static readonly RgbaVector DarkCyan = NamedColors.DarkCyan; - - /// - /// Represents a matching the W3C definition that has an hex value of #B8860B. - /// - public static readonly RgbaVector DarkGoldenrod = NamedColors.DarkGoldenrod; - - /// - /// Represents a matching the W3C definition that has an hex value of #A9A9A9. - /// - public static readonly RgbaVector DarkGray = NamedColors.DarkGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #006400. - /// - public static readonly RgbaVector DarkGreen = NamedColors.DarkGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #BDB76B. - /// - public static readonly RgbaVector DarkKhaki = NamedColors.DarkKhaki; - - /// - /// Represents a matching the W3C definition that has an hex value of #8B008B. - /// - public static readonly RgbaVector DarkMagenta = NamedColors.DarkMagenta; - - /// - /// Represents a matching the W3C definition that has an hex value of #556B2F. - /// - public static readonly RgbaVector DarkOliveGreen = NamedColors.DarkOliveGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF8C00. - /// - public static readonly RgbaVector DarkOrange = NamedColors.DarkOrange; - - /// - /// Represents a matching the W3C definition that has an hex value of #9932CC. - /// - public static readonly RgbaVector DarkOrchid = NamedColors.DarkOrchid; - - /// - /// Represents a matching the W3C definition that has an hex value of #8B0000. - /// - public static readonly RgbaVector DarkRed = NamedColors.DarkRed; - - /// - /// Represents a matching the W3C definition that has an hex value of #E9967A. - /// - public static readonly RgbaVector DarkSalmon = NamedColors.DarkSalmon; - - /// - /// Represents a matching the W3C definition that has an hex value of #8FBC8B. - /// - public static readonly RgbaVector DarkSeaGreen = NamedColors.DarkSeaGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #483D8B. - /// - public static readonly RgbaVector DarkSlateBlue = NamedColors.DarkSlateBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #2F4F4F. - /// - public static readonly RgbaVector DarkSlateGray = NamedColors.DarkSlateGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #00CED1. - /// - public static readonly RgbaVector DarkTurquoise = NamedColors.DarkTurquoise; - - /// - /// Represents a matching the W3C definition that has an hex value of #9400D3. - /// - public static readonly RgbaVector DarkViolet = NamedColors.DarkViolet; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF1493. - /// - public static readonly RgbaVector DeepPink = NamedColors.DeepPink; - - /// - /// Represents a matching the W3C definition that has an hex value of #00BFFF. - /// - public static readonly RgbaVector DeepSkyBlue = NamedColors.DeepSkyBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #696969. - /// - public static readonly RgbaVector DimGray = NamedColors.DimGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #1E90FF. - /// - public static readonly RgbaVector DodgerBlue = NamedColors.DodgerBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #B22222. - /// - public static readonly RgbaVector Firebrick = NamedColors.Firebrick; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFAF0. - /// - public static readonly RgbaVector FloralWhite = NamedColors.FloralWhite; - - /// - /// Represents a matching the W3C definition that has an hex value of #228B22. - /// - public static readonly RgbaVector ForestGreen = NamedColors.ForestGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF00FF. - /// - public static readonly RgbaVector Fuchsia = NamedColors.Fuchsia; - - /// - /// Represents a matching the W3C definition that has an hex value of #DCDCDC. - /// - public static readonly RgbaVector Gainsboro = NamedColors.Gainsboro; - - /// - /// Represents a matching the W3C definition that has an hex value of #F8F8FF. - /// - public static readonly RgbaVector GhostWhite = NamedColors.GhostWhite; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFD700. - /// - public static readonly RgbaVector Gold = NamedColors.Gold; - - /// - /// Represents a matching the W3C definition that has an hex value of #DAA520. - /// - public static readonly RgbaVector Goldenrod = NamedColors.Goldenrod; - - /// - /// Represents a matching the W3C definition that has an hex value of #808080. - /// - public static readonly RgbaVector Gray = NamedColors.Gray; - - /// - /// Represents a matching the W3C definition that has an hex value of #008000. - /// - public static readonly RgbaVector Green = NamedColors.Green; - - /// - /// Represents a matching the W3C definition that has an hex value of #ADFF2F. - /// - public static readonly RgbaVector GreenYellow = NamedColors.GreenYellow; - - /// - /// Represents a matching the W3C definition that has an hex value of #F0FFF0. - /// - public static readonly RgbaVector Honeydew = NamedColors.Honeydew; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF69B4. - /// - public static readonly RgbaVector HotPink = NamedColors.HotPink; - - /// - /// Represents a matching the W3C definition that has an hex value of #CD5C5C. - /// - public static readonly RgbaVector IndianRed = NamedColors.IndianRed; - - /// - /// Represents a matching the W3C definition that has an hex value of #4B0082. - /// - public static readonly RgbaVector Indigo = NamedColors.Indigo; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFFF0. - /// - public static readonly RgbaVector Ivory = NamedColors.Ivory; - - /// - /// Represents a matching the W3C definition that has an hex value of #F0E68C. - /// - public static readonly RgbaVector Khaki = NamedColors.Khaki; - - /// - /// Represents a matching the W3C definition that has an hex value of #E6E6FA. - /// - public static readonly RgbaVector Lavender = NamedColors.Lavender; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFF0F5. - /// - public static readonly RgbaVector LavenderBlush = NamedColors.LavenderBlush; - - /// - /// Represents a matching the W3C definition that has an hex value of #7CFC00. - /// - public static readonly RgbaVector LawnGreen = NamedColors.LawnGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFACD. - /// - public static readonly RgbaVector LemonChiffon = NamedColors.LemonChiffon; - - /// - /// Represents a matching the W3C definition that has an hex value of #ADD8E6. - /// - public static readonly RgbaVector LightBlue = NamedColors.LightBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #F08080. - /// - public static readonly RgbaVector LightCoral = NamedColors.LightCoral; - - /// - /// Represents a matching the W3C definition that has an hex value of #E0FFFF. - /// - public static readonly RgbaVector LightCyan = NamedColors.LightCyan; - - /// - /// Represents a matching the W3C definition that has an hex value of #FAFAD2. - /// - public static readonly RgbaVector LightGoldenrodYellow = NamedColors.LightGoldenrodYellow; - - /// - /// Represents a matching the W3C definition that has an hex value of #D3D3D3. - /// - public static readonly RgbaVector LightGray = NamedColors.LightGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #90EE90. - /// - public static readonly RgbaVector LightGreen = NamedColors.LightGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFB6C1. - /// - public static readonly RgbaVector LightPink = NamedColors.LightPink; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFA07A. - /// - public static readonly RgbaVector LightSalmon = NamedColors.LightSalmon; - - /// - /// Represents a matching the W3C definition that has an hex value of #20B2AA. - /// - public static readonly RgbaVector LightSeaGreen = NamedColors.LightSeaGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #87CEFA. - /// - public static readonly RgbaVector LightSkyBlue = NamedColors.LightSkyBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #778899. - /// - public static readonly RgbaVector LightSlateGray = NamedColors.LightSlateGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #B0C4DE. - /// - public static readonly RgbaVector LightSteelBlue = NamedColors.LightSteelBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFFE0. - /// - public static readonly RgbaVector LightYellow = NamedColors.LightYellow; - - /// - /// Represents a matching the W3C definition that has an hex value of #00FF00. - /// - public static readonly RgbaVector Lime = NamedColors.Lime; - - /// - /// Represents a matching the W3C definition that has an hex value of #32CD32. - /// - public static readonly RgbaVector LimeGreen = NamedColors.LimeGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FAF0E6. - /// - public static readonly RgbaVector Linen = NamedColors.Linen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF00FF. - /// - public static readonly RgbaVector Magenta = NamedColors.Magenta; - - /// - /// Represents a matching the W3C definition that has an hex value of #800000. - /// - public static readonly RgbaVector Maroon = NamedColors.Maroon; - - /// - /// Represents a matching the W3C definition that has an hex value of #66CDAA. - /// - public static readonly RgbaVector MediumAquamarine = NamedColors.MediumAquamarine; - - /// - /// Represents a matching the W3C definition that has an hex value of #0000CD. - /// - public static readonly RgbaVector MediumBlue = NamedColors.MediumBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #BA55D3. - /// - public static readonly RgbaVector MediumOrchid = NamedColors.MediumOrchid; - - /// - /// Represents a matching the W3C definition that has an hex value of #9370DB. - /// - public static readonly RgbaVector MediumPurple = NamedColors.MediumPurple; - - /// - /// Represents a matching the W3C definition that has an hex value of #3CB371. - /// - public static readonly RgbaVector MediumSeaGreen = NamedColors.MediumSeaGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #7B68EE. - /// - public static readonly RgbaVector MediumSlateBlue = NamedColors.MediumSlateBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #00FA9A. - /// - public static readonly RgbaVector MediumSpringGreen = NamedColors.MediumSpringGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #48D1CC. - /// - public static readonly RgbaVector MediumTurquoise = NamedColors.MediumTurquoise; - - /// - /// Represents a matching the W3C definition that has an hex value of #C71585. - /// - public static readonly RgbaVector MediumVioletRed = NamedColors.MediumVioletRed; - - /// - /// Represents a matching the W3C definition that has an hex value of #191970. - /// - public static readonly RgbaVector MidnightBlue = NamedColors.MidnightBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #F5FFFA. - /// - public static readonly RgbaVector MintCream = NamedColors.MintCream; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFE4E1. - /// - public static readonly RgbaVector MistyRose = NamedColors.MistyRose; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFE4B5. - /// - public static readonly RgbaVector Moccasin = NamedColors.Moccasin; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFDEAD. - /// - public static readonly RgbaVector NavajoWhite = NamedColors.NavajoWhite; - - /// - /// Represents a matching the W3C definition that has an hex value of #000080. - /// - public static readonly RgbaVector Navy = NamedColors.Navy; - - /// - /// Represents a matching the W3C definition that has an hex value of #FDF5E6. - /// - public static readonly RgbaVector OldLace = NamedColors.OldLace; - - /// - /// Represents a matching the W3C definition that has an hex value of #808000. - /// - public static readonly RgbaVector Olive = NamedColors.Olive; - - /// - /// Represents a matching the W3C definition that has an hex value of #6B8E23. - /// - public static readonly RgbaVector OliveDrab = NamedColors.OliveDrab; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFA500. - /// - public static readonly RgbaVector Orange = NamedColors.Orange; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF4500. - /// - public static readonly RgbaVector OrangeRed = NamedColors.OrangeRed; - - /// - /// Represents a matching the W3C definition that has an hex value of #DA70D6. - /// - public static readonly RgbaVector Orchid = NamedColors.Orchid; - - /// - /// Represents a matching the W3C definition that has an hex value of #EEE8AA. - /// - public static readonly RgbaVector PaleGoldenrod = NamedColors.PaleGoldenrod; - - /// - /// Represents a matching the W3C definition that has an hex value of #98FB98. - /// - public static readonly RgbaVector PaleGreen = NamedColors.PaleGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #AFEEEE. - /// - public static readonly RgbaVector PaleTurquoise = NamedColors.PaleTurquoise; - - /// - /// Represents a matching the W3C definition that has an hex value of #DB7093. - /// - public static readonly RgbaVector PaleVioletRed = NamedColors.PaleVioletRed; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFEFD5. - /// - public static readonly RgbaVector PapayaWhip = NamedColors.PapayaWhip; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFDAB9. - /// - public static readonly RgbaVector PeachPuff = NamedColors.PeachPuff; - - /// - /// Represents a matching the W3C definition that has an hex value of #CD853F. - /// - public static readonly RgbaVector Peru = NamedColors.Peru; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFC0CB. - /// - public static readonly RgbaVector Pink = NamedColors.Pink; - - /// - /// Represents a matching the W3C definition that has an hex value of #DDA0DD. - /// - public static readonly RgbaVector Plum = NamedColors.Plum; - - /// - /// Represents a matching the W3C definition that has an hex value of #B0E0E6. - /// - public static readonly RgbaVector PowderBlue = NamedColors.PowderBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #800080. - /// - public static readonly RgbaVector Purple = NamedColors.Purple; - - /// - /// Represents a matching the W3C definition that has an hex value of #663399. - /// - public static readonly RgbaVector RebeccaPurple = NamedColors.RebeccaPurple; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF0000. - /// - public static readonly RgbaVector Red = NamedColors.Red; - - /// - /// Represents a matching the W3C definition that has an hex value of #BC8F8F. - /// - public static readonly RgbaVector RosyBrown = NamedColors.RosyBrown; - - /// - /// Represents a matching the W3C definition that has an hex value of #4169E1. - /// - public static readonly RgbaVector RoyalBlue = NamedColors.RoyalBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #8B4513. - /// - public static readonly RgbaVector SaddleBrown = NamedColors.SaddleBrown; - - /// - /// Represents a matching the W3C definition that has an hex value of #FA8072. - /// - public static readonly RgbaVector Salmon = NamedColors.Salmon; - - /// - /// Represents a matching the W3C definition that has an hex value of #F4A460. - /// - public static readonly RgbaVector SandyBrown = NamedColors.SandyBrown; - - /// - /// Represents a matching the W3C definition that has an hex value of #2E8B57. - /// - public static readonly RgbaVector SeaGreen = NamedColors.SeaGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFF5EE. - /// - public static readonly RgbaVector SeaShell = NamedColors.SeaShell; - - /// - /// Represents a matching the W3C definition that has an hex value of #A0522D. - /// - public static readonly RgbaVector Sienna = NamedColors.Sienna; - - /// - /// Represents a matching the W3C definition that has an hex value of #C0C0C0. - /// - public static readonly RgbaVector Silver = NamedColors.Silver; - - /// - /// Represents a matching the W3C definition that has an hex value of #87CEEB. - /// - public static readonly RgbaVector SkyBlue = NamedColors.SkyBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #6A5ACD. - /// - public static readonly RgbaVector SlateBlue = NamedColors.SlateBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #708090. - /// - public static readonly RgbaVector SlateGray = NamedColors.SlateGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFAFA. - /// - public static readonly RgbaVector Snow = NamedColors.Snow; - - /// - /// Represents a matching the W3C definition that has an hex value of #00FF7F. - /// - public static readonly RgbaVector SpringGreen = NamedColors.SpringGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #4682B4. - /// - public static readonly RgbaVector SteelBlue = NamedColors.SteelBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #D2B48C. - /// - public static readonly RgbaVector Tan = NamedColors.Tan; - - /// - /// Represents a matching the W3C definition that has an hex value of #008080. - /// - public static readonly RgbaVector Teal = NamedColors.Teal; - - /// - /// Represents a matching the W3C definition that has an hex value of #D8BFD8. - /// - public static readonly RgbaVector Thistle = NamedColors.Thistle; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF6347. - /// - public static readonly RgbaVector Tomato = NamedColors.Tomato; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFFFF. - /// - public static readonly RgbaVector Transparent = NamedColors.Transparent; - - /// - /// Represents a matching the W3C definition that has an hex value of #40E0D0. - /// - public static readonly RgbaVector Turquoise = NamedColors.Turquoise; - - /// - /// Represents a matching the W3C definition that has an hex value of #EE82EE. - /// - public static readonly RgbaVector Violet = NamedColors.Violet; - - /// - /// Represents a matching the W3C definition that has an hex value of #F5DEB3. - /// - public static readonly RgbaVector Wheat = NamedColors.Wheat; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFFFF. - /// - public static readonly RgbaVector White = NamedColors.White; - - /// - /// Represents a matching the W3C definition that has an hex value of #F5F5F5. - /// - public static readonly RgbaVector WhiteSmoke = NamedColors.WhiteSmoke; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFF00. - /// - public static readonly RgbaVector Yellow = NamedColors.Yellow; - - /// - /// Represents a matching the W3C definition that has an hex value of #9ACD32. - /// - public static readonly RgbaVector YellowGreen = NamedColors.YellowGreen; - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs index ce40665cd4..aae6ee6940 100644 --- a/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs @@ -18,11 +18,23 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override unsafe void ToVector4(ReadOnlySpan sourceColors, Span destVectors, int count) + internal override void PackFromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) { - GuardSpans(sourceColors, nameof(sourceColors), destVectors, nameof(destVectors), count); + GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); - MemoryMarshal.Cast(sourceColors).Slice(0, count).CopyTo(destVectors); + MemoryMarshal.Cast(sourceVectors).Slice(0, count).CopyTo(destinationColors); + } + + /// + internal override void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) + => this.ToVector4(sourceColors, destinationVectors, count); + + /// + internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) + { + GuardSpans(sourceColors, nameof(sourceColors), destinationVectors, nameof(destinationVectors), count); + + MemoryMarshal.Cast(sourceColors).Slice(0, count).CopyTo(destinationVectors); } } } diff --git a/src/ImageSharp/PixelFormats/RgbaVector.cs b/src/ImageSharp/PixelFormats/RgbaVector.cs index 5ca0ce406f..b5ccf8aedc 100644 --- a/src/ImageSharp/PixelFormats/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/RgbaVector.cs @@ -96,7 +96,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static RgbaVector FromHex(string hex) => ColorBuilder.FromHex(hex); /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -125,6 +125,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -137,6 +141,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Short2.cs b/src/ImageSharp/PixelFormats/Short2.cs index 24430a5d9f..db29b401ed 100644 --- a/src/ImageSharp/PixelFormats/Short2.cs +++ b/src/ImageSharp/PixelFormats/Short2.cs @@ -105,11 +105,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -119,10 +119,18 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Short4.cs b/src/ImageSharp/PixelFormats/Short4.cs index 4925137470..6d6e5f0845 100644 --- a/src/ImageSharp/PixelFormats/Short4.cs +++ b/src/ImageSharp/PixelFormats/Short4.cs @@ -110,11 +110,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -124,10 +124,18 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 92b04f587e..e9cc98884a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -13,20 +13,257 @@ using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests.PixelFormats { - public partial class PixelOperationsTests + public class PixelOperationsTests { - public class Rgba32 : PixelOperationsTests + public class Argb32OperationsTests : PixelOperationsTests { - public Rgba32(ITestOutputHelper output) + public Argb32OperationsTests(ITestOutputHelper output) : base(output) { } - // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: + // For 4.6 test runner MemberData does not work without redeclaring the public field in the + // derived test class: + // TODO: Can this not be delared in the parent class? public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + + public class Bgr24OperationsTests : PixelOperationsTests + { + public Bgr24OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + + public class Bgra32OperationsTests : PixelOperationsTests + { + public Bgra32OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + + public class Gray8OperationsTests : PixelOperationsTests + { + public Gray8OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromGray8Bytes(int count) + { + byte[] source = CreateByteTestData(count); + var expected = new Gray8[count]; + + for (int i = 0; i < count; i++) + { + expected[i].PackFromGray8(new Gray8(source[i])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromGray8Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray8Bytes(int count) + { + Gray8[] source = CreatePixelTestData(count); + byte[] expected = new byte[count]; + var gray = default(Gray8); + + for (int i = 0; i < count; i++) + { + gray.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i] = gray.PackedValue; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray8Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromGray16Bytes(int count) + { + byte[] source = CreateByteTestData(count * 2); + Span sourceSpan = source.AsSpan(); + var expected = new Gray8[count]; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + expected[i].PackFromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromGray16Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray16Bytes(int count) + { + Gray8[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 2]; + Gray16 gray = default; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + gray.PackFromScaledVector4(source[i].ToScaledVector4()); + OctetBytes bytes = Unsafe.As(ref gray); + expected[i2] = bytes[0]; + expected[i2 + 1] = bytes[1]; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray16Bytes(s, d.GetSpan(), count) + ); + } + } + + public class Gray16OperationsTests : PixelOperationsTests + { + public Gray16OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromGray8Bytes(int count) + { + byte[] source = CreateByteTestData(count); + var expected = new Gray16[count]; + + for (int i = 0; i < count; i++) + { + expected[i].PackFromGray8(new Gray8(source[i])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromGray8Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray8Bytes(int count) + { + Gray16[] source = CreatePixelTestData(count); + byte[] expected = new byte[count]; + var gray = default(Gray8); + + for (int i = 0; i < count; i++) + { + gray.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i] = gray.PackedValue; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray8Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromGray16Bytes(int count) + { + byte[] source = CreateByteTestData(count * 2); + Span sourceSpan = source.AsSpan(); + var expected = new Gray16[count]; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + expected[i].PackFromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromGray16Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray16Bytes(int count) + { + Gray16[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 2]; + Gray16 gray = default; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + gray.PackFromScaledVector4(source[i].ToScaledVector4()); + OctetBytes bytes = Unsafe.As(ref gray); + expected[i2] = bytes[0]; + expected[i2 + 1] = bytes[1]; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray16Bytes(s, d.GetSpan(), count) + ); + } + } + + public class Rgba32OperationsTests : PixelOperationsTests + { + public Rgba32OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); [Fact] public void ToVector4SimdAligned() @@ -36,63 +273,86 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats return; } - ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(64); + Rgba32[] source = CreatePixelTestData(64); Vector4[] expected = CreateExpectedVector4Data(source); TestOperation( source, expected, - (s, d) => ImageSharp.PixelFormats.Rgba32.PixelOperations.ToVector4SimdAligned(s, d.GetSpan(), 64) + (s, d) => Rgba32.PixelOperations.ToVector4SimdAligned(s, d.GetSpan(), 64) ); } - // [Fact] // Profiling benchmark - enable manually! #pragma warning disable xUnit1013 // Public method should be marked as test public void Benchmark_ToVector4() #pragma warning restore xUnit1013 // Public method should be marked as test { - int times = 200000; - int count = 1024; + const int times = 200000; + const int count = 1024; - using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) + using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) using (IMemoryOwner dest = Configuration.Default.MemoryAllocator.Allocate(count)) { this.Measure( times, - () => - { - PixelOperations.Instance.ToVector4(source.GetSpan(), dest.GetSpan(), count); - }); + () => PixelOperations.Instance.ToVector4(source.GetSpan(), dest.GetSpan(), count)); } } } - public class Argb32 : PixelOperationsTests + public class Rgb48OperationsTests : PixelOperationsTests { - // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: - public Argb32(ITestOutputHelper output) + public Rgb48OperationsTests(ITestOutputHelper output) : base(output) { } public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + + public class Rgba64OperationsTests : PixelOperationsTests + { + public Rgba64OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + + public class RgbaVectorOperationsTests : PixelOperationsTests + { + public RgbaVectorOperationsTests(ITestOutputHelper output) + : base(output) + { + } + + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); } [Theory] [WithBlankImages(1, 1, PixelTypes.All)] - public void GetGlobalInstance(TestImageProvider dummy) + public void GetGlobalInstance(TestImageProvider _) where TPixel : struct, IPixel => Assert.NotNull(PixelOperations.Instance); [Fact] public void IsOpaqueColor() { - Assert.True(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); - - Assert.False(new GraphicsOptions(true, 0.5f).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); - Assert.False(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Transparent)); - Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Lighten, 1).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); - Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); + Assert.True(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions(true, 0.5f).IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Transparent)); + Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Lighten, 1).IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(Rgba32.Red)); } } @@ -106,7 +366,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public static TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - private static PixelOperations Operations => PixelOperations.Instance; + internal static PixelOperations Operations => PixelOperations.Instance; internal static TPixel[] CreateExpectedPixelData(Vector4[] source) { @@ -210,383 +470,333 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgb24Bytes(int count) + public void PackFromArgb32Bytes(int count) { - byte[] source = CreateByteTestData(count * 3); + byte[] source = CreateByteTestData(count * 4); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i3 = i * 3; + int i4 = i * 4; - expected[i].PackFromRgba32(new Rgba32(source[i3 + 0], source[i3 + 1], source[i3 + 2], 255)); + expected[i].PackFromArgb32(new Argb32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); } TestOperation( source, expected, - (s, d) => Operations.PackFromRgb24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.PackFromArgb32Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToRgb24Bytes(int count) + public void ToArgb32Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 3]; - var rgb = default(Rgb24); + byte[] expected = new byte[count * 4]; + var argb = default(Argb32); for (int i = 0; i < count; i++) { - int i3 = i * 3; - rgb.PackFromScaledVector4(source[i].ToScaledVector4()); - expected[i3] = rgb.R; - expected[i3 + 1] = rgb.G; - expected[i3 + 2] = rgb.B; + int i4 = i * 4; + argb.PackFromScaledVector4(source[i].ToScaledVector4()); + + expected[i4] = argb.A; + expected[i4 + 1] = argb.R; + expected[i4 + 2] = argb.G; + expected[i4 + 3] = argb.B; } TestOperation( source, expected, - (s, d) => Operations.ToRgb24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToArgb32Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgba32Bytes(int count) + public void PackFromBgr24Bytes(int count) { - byte[] source = CreateByteTestData(count * 4); + byte[] source = CreateByteTestData(count * 3); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i4 = i * 4; + int i3 = i * 3; - expected[i].PackFromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); + expected[i].PackFromBgr24(new Bgr24(source[i3 + 2], source[i3 + 1], source[i3])); } TestOperation( source, expected, - (s, d) => Operations.PackFromRgba32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.PackFromBgr24Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToRgba32Bytes(int count) + public void ToBgr24Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var rgba = default(Rgba32); + byte[] expected = new byte[count * 3]; + var bgr = default(Bgr24); for (int i = 0; i < count; i++) { - int i4 = i * 4; - rgba.PackFromScaledVector4(source[i].ToScaledVector4()); - expected[i4] = rgba.R; - expected[i4 + 1] = rgba.G; - expected[i4 + 2] = rgba.B; - expected[i4 + 3] = rgba.A; + int i3 = i * 3; + bgr.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i3] = bgr.B; + expected[i3 + 1] = bgr.G; + expected[i3 + 2] = bgr.R; } TestOperation( source, expected, - (s, d) => Operations.ToRgba32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToBgr24Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgb48Bytes(int count) + public void PackFromBgra32Bytes(int count) { - byte[] source = CreateByteTestData(count * 6); - Span sourceSpan = source.AsSpan(); + byte[] source = CreateByteTestData(count * 4); var expected = new TPixel[count]; - var rgba64 = new Rgba64(0, 0, 0, 65535); for (int i = 0; i < count; i++) { - int i6 = i * 6; - rgba64.Rgb = MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]; - expected[i].PackFromRgba64(rgba64); + int i4 = i * 4; + + expected[i].PackFromBgra32(new Bgra32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); } TestOperation( source, expected, - (s, d) => Operations.PackFromRgb48Bytes(s, d.GetSpan(), count) + (s, d) => Operations.PackFromBgra32Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToRgb48Bytes(int count) + public void ToBgra32Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 6]; - Rgb48 rgb = default; + byte[] expected = new byte[count * 4]; + var bgra = default(Bgra32); for (int i = 0; i < count; i++) { - int i6 = i * 6; - rgb.PackFromScaledVector4(source[i].ToScaledVector4()); - Rgba64Bytes rgb48Bytes = Unsafe.As(ref rgb); - expected[i6] = rgb48Bytes[0]; - expected[i6 + 1] = rgb48Bytes[1]; - expected[i6 + 2] = rgb48Bytes[2]; - expected[i6 + 3] = rgb48Bytes[3]; - expected[i6 + 4] = rgb48Bytes[4]; - expected[i6 + 5] = rgb48Bytes[5]; + int i4 = i * 4; + bgra.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i4] = bgra.B; + expected[i4 + 1] = bgra.G; + expected[i4 + 2] = bgra.R; + expected[i4 + 3] = bgra.A; } TestOperation( source, expected, - (s, d) => Operations.ToRgb48Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToBgra32Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgba64Bytes(int count) + public void PackFromRgb24Bytes(int count) { - byte[] source = CreateByteTestData(count * 8); - Span sourceSpan = source.AsSpan(); + byte[] source = CreateByteTestData(count * 3); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i8 = i * 8; - expected[i].PackFromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); + int i3 = i * 3; + + expected[i].PackFromRgb24(new Rgb24(source[i3 + 0], source[i3 + 1], source[i3 + 2])); } TestOperation( source, expected, - (s, d) => Operations.PackFromRgba64Bytes(s, d.GetSpan(), count) + (s, d) => Operations.PackFromRgb24Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToRgba64Bytes(int count) + public void ToRgb24Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 8]; - Rgba64 rgba = default; + byte[] expected = new byte[count * 3]; + var rgb = default(Rgb24); for (int i = 0; i < count; i++) { - int i8 = i * 8; - rgba.PackFromScaledVector4(source[i].ToScaledVector4()); - Rgba64Bytes rgba64Bytes = Unsafe.As(ref rgba); - expected[i8] = rgba64Bytes[0]; - expected[i8 + 1] = rgba64Bytes[1]; - expected[i8 + 2] = rgba64Bytes[2]; - expected[i8 + 3] = rgba64Bytes[3]; - expected[i8 + 4] = rgba64Bytes[4]; - expected[i8 + 5] = rgba64Bytes[5]; - expected[i8 + 6] = rgba64Bytes[6]; - expected[i8 + 7] = rgba64Bytes[7]; + int i3 = i * 3; + rgb.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i3] = rgb.R; + expected[i3 + 1] = rgb.G; + expected[i3 + 2] = rgb.B; } TestOperation( source, expected, - (s, d) => Operations.ToRgba64Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgb24Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromBgr24Bytes(int count) + public void PackFromRgba32Bytes(int count) { - byte[] source = CreateByteTestData(count * 3); + byte[] source = CreateByteTestData(count * 4); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i3 = i * 3; + int i4 = i * 4; - expected[i].PackFromRgba32(new Rgba32(source[i3 + 2], source[i3 + 1], source[i3 + 0], 255)); + expected[i].PackFromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); } TestOperation( source, expected, - (s, d) => Operations.PackFromBgr24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.PackFromRgba32Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToBgr24Bytes(int count) + public void ToRgba32Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 3]; - var bgr = default(Bgr24); + byte[] expected = new byte[count * 4]; + var rgba = default(Rgba32); for (int i = 0; i < count; i++) { - int i3 = i * 3; - bgr.PackFromScaledVector4(source[i].ToScaledVector4()); - expected[i3] = bgr.B; - expected[i3 + 1] = bgr.G; - expected[i3 + 2] = bgr.R; + int i4 = i * 4; + rgba.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i4] = rgba.R; + expected[i4 + 1] = rgba.G; + expected[i4 + 2] = rgba.B; + expected[i4 + 3] = rgba.A; } TestOperation( source, expected, - (s, d) => Operations.ToBgr24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgba32Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromBgra32Bytes(int count) + public void PackFromRgb48Bytes(int count) { - byte[] source = CreateByteTestData(count * 4); + byte[] source = CreateByteTestData(count * 6); + Span sourceSpan = source.AsSpan(); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i4 = i * 4; - - expected[i].PackFromRgba32(new Rgba32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); + int i6 = i * 6; + expected[i].PackFromRgb48(MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]); } TestOperation( source, expected, - (s, d) => Operations.PackFromBgra32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.PackFromRgb48Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToBgra32Bytes(int count) + public void ToRgb48Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var bgra = default(Bgra32); + byte[] expected = new byte[count * 6]; + Rgb48 rgb = default; for (int i = 0; i < count; i++) { - int i4 = i * 4; - bgra.PackFromScaledVector4(source[i].ToScaledVector4()); - expected[i4] = bgra.B; - expected[i4 + 1] = bgra.G; - expected[i4 + 2] = bgra.R; - expected[i4 + 3] = bgra.A; + int i6 = i * 6; + rgb.PackFromScaledVector4(source[i].ToScaledVector4()); + OctetBytes rgb48Bytes = Unsafe.As(ref rgb); + expected[i6] = rgb48Bytes[0]; + expected[i6 + 1] = rgb48Bytes[1]; + expected[i6 + 2] = rgb48Bytes[2]; + expected[i6 + 3] = rgb48Bytes[3]; + expected[i6 + 4] = rgb48Bytes[4]; + expected[i6 + 5] = rgb48Bytes[5]; } TestOperation( source, expected, - (s, d) => Operations.ToBgra32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgb48Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromArgb32Bytes(int count) + public void PackFromRgba64Bytes(int count) { - byte[] source = CreateByteTestData(count * 4); + byte[] source = CreateByteTestData(count * 8); + Span sourceSpan = source.AsSpan(); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i4 = i * 4; - - expected[i].PackFromRgba32(new Rgba32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); + int i8 = i * 8; + expected[i].PackFromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); } TestOperation( source, expected, - (s, d) => Operations.PackFromArgb32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.PackFromRgba64Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToArgb32Bytes(int count) + public void ToRgba64Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var argb = default(Argb32); + byte[] expected = new byte[count * 8]; + Rgba64 rgba = default; for (int i = 0; i < count; i++) { - int i4 = i * 4; - argb.PackFromScaledVector4(source[i].ToScaledVector4()); - - expected[i4] = argb.A; - expected[i4 + 1] = argb.R; - expected[i4 + 2] = argb.G; - expected[i4 + 3] = argb.B; + int i8 = i * 8; + rgba.PackFromScaledVector4(source[i].ToScaledVector4()); + OctetBytes rgba64Bytes = Unsafe.As(ref rgba); + expected[i8] = rgba64Bytes[0]; + expected[i8 + 1] = rgba64Bytes[1]; + expected[i8 + 2] = rgba64Bytes[2]; + expected[i8 + 3] = rgba64Bytes[3]; + expected[i8 + 4] = rgba64Bytes[4]; + expected[i8 + 5] = rgba64Bytes[5]; + expected[i8 + 6] = rgba64Bytes[6]; + expected[i8 + 7] = rgba64Bytes[7]; } TestOperation( source, expected, - (s, d) => Operations.ToArgb32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgba64Bytes(s, d.GetSpan(), count) ); } - private class TestBuffers : IDisposable - where TSource : struct - where TDest : struct - { - public TSource[] SourceBuffer { get; } - public IMemoryOwner ActualDestBuffer { get; } - public TDest[] ExpectedDestBuffer { get; } - - public TestBuffers(TSource[] source, TDest[] expectedDest) - { - this.SourceBuffer = source; - this.ExpectedDestBuffer = expectedDest; - this.ActualDestBuffer = Configuration.Default.MemoryAllocator.Allocate(expectedDest.Length); - } - - public void Dispose() => this.ActualDestBuffer.Dispose(); - - private const float Tolerance = 0.0001f; - - public void Verify() - { - int count = this.ExpectedDestBuffer.Length; - - if (typeof(TDest) == typeof(Vector4)) - { - - Span expected = MemoryMarshal.Cast(this.ExpectedDestBuffer.AsSpan()); - Span actual = MemoryMarshal.Cast(this.ActualDestBuffer.GetSpan()); - - for (int i = 0; i < count; i++) - { - // ReSharper disable PossibleNullReferenceException - Assert.Equal(expected[i], actual[i], new ApproximateFloatComparer(0.001f)); - // ReSharper restore PossibleNullReferenceException - } - } - else - { - Span expected = this.ExpectedDestBuffer.AsSpan(); - Span actual = this.ActualDestBuffer.GetSpan(); - for (int i = 0; i < count; i++) - { - Assert.Equal(expected[i], actual[i]); - } - } - } - } - internal static void TestOperation( TSource[] source, TDest[] expected, @@ -666,7 +876,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [StructLayout(LayoutKind.Sequential)] - private unsafe struct Rgba64Bytes + internal unsafe struct OctetBytes { public fixed byte Data[8]; @@ -675,10 +885,56 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - ref byte self = ref Unsafe.As(ref this); + ref byte self = ref Unsafe.As(ref this); return Unsafe.Add(ref self, idx); } } } + + private class TestBuffers : IDisposable + where TSource : struct + where TDest : struct + { + public TSource[] SourceBuffer { get; } + public IMemoryOwner ActualDestBuffer { get; } + public TDest[] ExpectedDestBuffer { get; } + + public TestBuffers(TSource[] source, TDest[] expectedDest) + { + this.SourceBuffer = source; + this.ExpectedDestBuffer = expectedDest; + this.ActualDestBuffer = Configuration.Default.MemoryAllocator.Allocate(expectedDest.Length); + } + + public void Dispose() => this.ActualDestBuffer.Dispose(); + + public void Verify() + { + int count = this.ExpectedDestBuffer.Length; + + if (typeof(TDest) == typeof(Vector4)) + { + Span expected = MemoryMarshal.Cast(this.ExpectedDestBuffer.AsSpan()); + Span actual = MemoryMarshal.Cast(this.ActualDestBuffer.GetSpan()); + + var comparer = new ApproximateFloatComparer(0.001f); + for (int i = 0; i < count; i++) + { + // ReSharper disable PossibleNullReferenceException + Assert.Equal(expected[i], actual[i], comparer); + // ReSharper restore PossibleNullReferenceException + } + } + else + { + Span expected = this.ExpectedDestBuffer.AsSpan(); + Span actual = this.ActualDestBuffer.GetSpan(); + for (int i = 0; i < count; i++) + { + Assert.Equal(expected[i], actual[i]); + } + } + } + } } } \ No newline at end of file From d4bda602ce1739aa03dde5960a6b42fe997b5c00 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 15 Oct 2018 19:53:28 +0100 Subject: [PATCH 155/381] Fix sandbox tests --- tests/ImageSharp.Sandbox46/Program.cs | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/tests/ImageSharp.Sandbox46/Program.cs b/tests/ImageSharp.Sandbox46/Program.cs index fa1d63878a..4d89929a03 100644 --- a/tests/ImageSharp.Sandbox46/Program.cs +++ b/tests/ImageSharp.Sandbox46/Program.cs @@ -6,14 +6,9 @@ namespace SixLabors.ImageSharp.Sandbox46 { using System; - using System.Runtime.DesignerServices; - - using SixLabors.ImageSharp.Tests; - using SixLabors.ImageSharp.Tests.Colors; using SixLabors.ImageSharp.Tests.Formats.Jpg; using SixLabors.ImageSharp.Tests.PixelFormats; using SixLabors.ImageSharp.Tests.Processing.Processors.Transforms; - using SixLabors.ImageSharp.Tests.Processing.Transforms; using Xunit.Abstractions; @@ -21,15 +16,9 @@ namespace SixLabors.ImageSharp.Sandbox46 { private class ConsoleOutput : ITestOutputHelper { - public void WriteLine(string message) - { - Console.WriteLine(message); - } + public void WriteLine(string message) => Console.WriteLine(message); - public void WriteLine(string format, params object[] args) - { - Console.WriteLine(format, args); - } + public void WriteLine(string format, params object[] args) => Console.WriteLine(format, args); } /// @@ -58,20 +47,20 @@ namespace SixLabors.ImageSharp.Sandbox46 private static void RunResizeProfilingTest() { - ResizeProfilingBenchmarks test = new ResizeProfilingBenchmarks(new ConsoleOutput()); + var test = new ResizeProfilingBenchmarks(new ConsoleOutput()); test.ResizeBicubic(2000, 2000); } private static void RunToVector4ProfilingTest() { - PixelOperationsTests.Rgba32 tests = new PixelOperationsTests.Rgba32(new ConsoleOutput()); + var tests = new PixelOperationsTests.Rgba32OperationsTests(new ConsoleOutput()); tests.Benchmark_ToVector4(); } private static void RunDecodeJpegProfilingTests() { Console.WriteLine("RunDecodeJpegProfilingTests..."); - JpegProfilingBenchmarks benchmarks = new JpegProfilingBenchmarks(new ConsoleOutput()); + var benchmarks = new JpegProfilingBenchmarks(new ConsoleOutput()); foreach (object[] data in JpegProfilingBenchmarks.DecodeJpegData) { string fileName = (string)data[0]; From b14c35ffafe2f762f0ee19cbca34982d638ed039 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 15 Oct 2018 22:29:39 +0100 Subject: [PATCH 156/381] Fix JIT issue on 32bit framework --- src/ImageSharp/PixelFormats/Rgba32.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index e7814d23ac..415c39c0ed 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -133,7 +133,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// public Rgb24 Rgb { - [MethodImpl(InliningOptions.ShortMethod)] + // If this is changed to ShortMethod then several jpeg encoding tests fail + // on 32 bit Net 4.6.2 and NET 4.7.1 + [MethodImpl(InliningOptions.ColdPath)] get => Unsafe.As(ref this); [MethodImpl(InliningOptions.ShortMethod)] From 3e5325e2b9e580a2617a36c8c3bbacef679f6de4 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 16 Oct 2018 00:35:45 +0200 Subject: [PATCH 157/381] uniformize conversion code --- .../SimdUtils.ExtendedIntrinsics.cs | 64 ++++++++++ src/ImageSharp/Common/Extensions/SimdUtils.cs | 50 ++------ .../PixelFormats/Rgba32.PixelOperations.cs | 117 +++--------------- .../Color/Bulk/PackFromVector4.cs | 4 +- .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 6 +- .../PixelFormats/PixelOperationsTests.cs | 38 ++---- 6 files changed, 103 insertions(+), 176 deletions(-) create mode 100644 src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs diff --git a/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs new file mode 100644 index 0000000000..ec52b90eff --- /dev/null +++ b/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs @@ -0,0 +1,64 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp +{ + internal static partial class SimdUtils + { + /// + /// Methods accelerated only in RyuJIT having dotnet/coreclr#10662 merged (.NET Core 2.1+ .NET 4.7.2+) + /// PR: + /// https://github.com/dotnet/coreclr/pull/10662 + /// API Proposal: + /// https://github.com/dotnet/corefx/issues/15957 + /// + public static class ExtendedIntrinsics + { + public static bool IsAvailable { get; } = +#if NETCOREAPP2_1 +// TODO: Add a build target for .NET 4.7.2 + true; +#else + false; +#endif + + // ReSharper disable once MemberHidesStaticFromOuterClass + internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + { + Guard.IsTrue( + source.Length % Vector.Count == 0, + nameof(source), + "dest.Length should be divisable by Vector.Count!"); + + int n = source.Length / Vector.Count; + + ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + Vector b = Unsafe.Add(ref sourceBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + Vector f0 = Vector.ConvertToSingle(w0) * scale; + Vector f1 = Vector.ConvertToSingle(w1) * scale; + Vector f2 = Vector.ConvertToSingle(w2) * scale; + Vector f3 = Vector.ConvertToSingle(w3) * scale; + + ref Vector d = ref Unsafe.Add(ref destBase, i * 4); + d = f0; + Unsafe.Add(ref d, 1) = f1; + Unsafe.Add(ref d, 2) = f2; + Unsafe.Add(ref d, 3) = f3; + } + } + } + } +} diff --git a/src/ImageSharp/Common/Extensions/SimdUtils.cs b/src/ImageSharp/Common/Extensions/SimdUtils.cs index 481e0726df..3630ede327 100644 --- a/src/ImageSharp/Common/Extensions/SimdUtils.cs +++ b/src/ImageSharp/Common/Extensions/SimdUtils.cs @@ -14,12 +14,12 @@ namespace SixLabors.ImageSharp /// /// Various extension and utility methods for and utilizing SIMD capabilities /// - internal static class SimdUtils + internal static partial class SimdUtils { /// /// Gets a value indicating whether the code is being executed on AVX2 CPU where both float and integer registers are of size 256 byte. /// - public static bool IsAvx2CompatibleArchitecture => Vector.Count == 8 && Vector.Count == 8; + public static bool IsAvx2CompatibleArchitecture { get; } = Vector.IsHardwareAccelerated && Vector.Count == 8 && Vector.Count == 8; internal static void GuardAvx2(string operation) { @@ -61,7 +61,8 @@ namespace SixLabors.ImageSharp /// /// Convert 'source.Length' values normalized into [0..1] from 'source' into 'dest' buffer of values. - /// The values gonna be scaled up into [0-255] and rounded. + /// The values are scaled up into [0-255] and rounded. + /// The implementation is SIMD optimized and works only with `source.Length` divisible by . /// Based on: /// /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions @@ -106,46 +107,13 @@ namespace SixLabors.ImageSharp } /// - /// Fast -> conversion for RyuJIT runtimes having dotnet/coreclr#10662 merged. + /// Converts `dest.Length` bytes to -s to -s normalized into [0..1] + /// The implementation is SIMD optimized and works only with `dest.Length` divisible by . + /// Implementation adapted from: /// - /// https://github.com/dotnet/coreclr/pull/10662 + /// http://stackoverflow.com/a/5362789 /// /// - internal static void BulkConvertByteToNormalizedFloatWithExtendedIntrinsics(ReadOnlySpan source, Span dest) - { - Guard.IsTrue( - source.Length % Vector.Count == 0, - nameof(source), - "dest.Length should be divisable by Vector.Count!"); - - int n = source.Length / Vector.Count; - - ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); - - var scale = new Vector(1f / 255f); - - for (int i = 0; i < n; i++) - { - Vector b = Unsafe.Add(ref sourceBase, i); - - Vector.Widen(b, out Vector s0, out Vector s1); - Vector.Widen(s0, out Vector w0, out Vector w1); - Vector.Widen(s1, out Vector w2, out Vector w3); - - Vector f0 = Vector.ConvertToSingle(w0) * scale; - Vector f1 = Vector.ConvertToSingle(w1) * scale; - Vector f2 = Vector.ConvertToSingle(w2) * scale; - Vector f3 = Vector.ConvertToSingle(w3) * scale; - - ref Vector d = ref Unsafe.Add(ref destBase, i * 4); - d = f0; - Unsafe.Add(ref d, 1) = f1; - Unsafe.Add(ref d, 2) = f2; - Unsafe.Add(ref d, 3) = f3; - } - } - internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { GuardAvx2(nameof(BulkConvertByteToNormalizedFloat)); @@ -188,7 +156,7 @@ namespace SixLabors.ImageSharp /// internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) { - GuardAvx2(nameof(BulkConvertNormalizedFloatToByte)); + GuardAvx2(nameof(BulkConvertNormalizedFloatToByteClampOverflows)); DebugGuard.IsTrue((source.Length % Vector.Count) == 0, nameof(source), "source.Length should be divisable by Vector.Count!"); diff --git a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs index 76e119ba44..6745079da5 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs @@ -3,7 +3,6 @@ using System; using System.Numerics; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.Memory; @@ -19,99 +18,37 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal partial class PixelOperations : PixelOperations { - /// - /// SIMD optimized bulk implementation of - /// that works only with `count` divisible by . - /// - /// The to the source colors. - /// The to the dstination vectors. - /// The number of pixels to convert. - /// - /// Implementation adapted from: - /// - /// http://stackoverflow.com/a/5362789 - /// - /// TODO: We can replace this implementation in the future using new Vector API-s: - /// - /// https://github.com/dotnet/corefx/issues/15957 - /// - /// - internal static void ToVector4SimdAligned(ReadOnlySpan sourceColors, Span destVectors, int count) - { - if (!Vector.IsHardwareAccelerated) - { - throw new InvalidOperationException( - "Rgba32.PixelOperations.ToVector4SimdAligned() should not be called when Vector.IsHardwareAccelerated == false!"); - } - - DebugGuard.IsTrue( - count % Vector.Count == 0, - nameof(count), - "Argument 'count' should divisible by Vector.Count!"); - - var bVec = new Vector(256.0f / 255.0f); - var magicFloat = new Vector(32768.0f); - var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f - var mask = new Vector(255); - - int unpackedRawCount = count * 4; - - ref uint sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference(sourceColors)); - ref WideRgba destBaseAsWide = ref Unsafe.As(ref MemoryMarshal.GetReference(destVectors)); - ref Vector destBaseAsUInt = ref Unsafe.As>(ref destBaseAsWide); - ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsWide); - - for (int i = 0; i < count; i++) - { - uint sVal = Unsafe.Add(ref sourceBase, i); - ref WideRgba dst = ref Unsafe.Add(ref destBaseAsWide, i); - - // This call is the bottleneck now: - dst.Load(sVal); - } - - int numOfVectors = unpackedRawCount / Vector.Count; - - for (int i = 0; i < numOfVectors; i++) - { - Vector vi = Unsafe.Add(ref destBaseAsUInt, i); - - vi &= mask; - vi |= magicInt; - - var vf = Vector.AsVectorSingle(vi); - vf = (vf - magicFloat) * bVec; - - Unsafe.Add(ref destBaseAsFloat, i) = vf; - } - } - /// internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) { Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); Guard.MustBeSizedAtLeast(destinationVectors, count, nameof(destinationVectors)); - if (count < 256 || !Vector.IsHardwareAccelerated) + if (count < 128 || !SimdUtils.IsAvx2CompatibleArchitecture) { // Doesn't worth to bother with SIMD: base.ToVector4(sourceColors, destinationVectors, count); return; } - int remainder = count % Vector.Count; + int remainder = count % 2; int alignedCount = count - remainder; if (alignedCount > 0) { - ToVector4SimdAligned(sourceColors, destinationVectors, alignedCount); + ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceColors); + Span rawDest = MemoryMarshal.Cast(destinationVectors.Slice(0, alignedCount)); + + SimdUtils.BulkConvertByteToNormalizedFloat( + rawSrc, + rawDest); } if (remainder > 0) { - sourceColors = sourceColors.Slice(alignedCount); - destinationVectors = destinationVectors.Slice(alignedCount); - base.ToVector4(sourceColors, destinationVectors, remainder); + // actually: remainder == 1 + int lastIdx = count - 1; + destinationVectors[lastIdx] = sourceColors[lastIdx].ToVector4(); } } @@ -120,7 +57,7 @@ namespace SixLabors.ImageSharp.PixelFormats { GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); - if (!SimdUtils.IsAvx2CompatibleArchitecture) + if (count < 128 || !SimdUtils.IsAvx2CompatibleArchitecture) { base.PackFromVector4(sourceVectors, destinationColors, count); return; @@ -131,10 +68,10 @@ namespace SixLabors.ImageSharp.PixelFormats if (alignedCount > 0) { - ReadOnlySpan flatSrc = MemoryMarshal.Cast(sourceVectors.Slice(0, alignedCount)); - Span flatDest = MemoryMarshal.Cast(destinationColors); + ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceVectors.Slice(0, alignedCount)); + Span rawDest = MemoryMarshal.Cast(destinationColors); - SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(flatSrc, flatDest); + SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(rawSrc, rawDest); } if (remainder > 0) @@ -172,30 +109,6 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(dest); } - - /// - /// Value type to store -s widened into multiple -s. - /// - [StructLayout(LayoutKind.Sequential)] - private struct WideRgba - { - private uint r; - - private uint g; - - private uint b; - - private uint a; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Load(uint p) - { - this.r = p; - this.g = p >> GreenShift; - this.b = p >> BlueShift; - this.a = p >> AlphaShift; - } - } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index a5fa59ba07..bdae7d0655 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -23,7 +23,9 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk private IMemoryOwner destination; - [Params(16, 128, 512)] + [Params( + //64, + 2048)] public int Count { get; set; } [GlobalSetup] diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index 4e39af70fd..0488dd5e15 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -205,12 +205,12 @@ namespace SixLabors.ImageSharp.Tests.Common Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); } - + [Theory] [InlineData(1, 0)] [InlineData(2, 32)] [InlineData(3, 128)] - public void BulkConvertByteToNormalizedFloatWithExtendedIntrinsics(int seed, int count) + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat(int seed, int count) { if (!Vector.IsHardwareAccelerated) { @@ -221,7 +221,7 @@ namespace SixLabors.ImageSharp.Tests.Common float[] result = new float[count]; float[] expected = source.Select(b => (float)b / 255f).ToArray(); - SimdUtils.BulkConvertByteToNormalizedFloatWithExtendedIntrinsics(source, result); + SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(source, result); Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 4d7ec71e72..535952e051 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -17,43 +17,26 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { public class Rgba32 : PixelOperationsTests { + public const string SkipProfilingBenchmarks = +#if true + "Profiling benchmark - enable manually!"; +#else + null; +#endif + public Rgba32(ITestOutputHelper output) : base(output) { } - // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - [Fact] public void IsSpecialImplementation() { Assert.IsType(PixelOperations.Instance); } - [Fact] - public void ToVector4SimdAligned() - { - if (!Vector.IsHardwareAccelerated) - { - return; - } - - ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(64); - Vector4[] expected = CreateExpectedVector4Data(source); - - TestOperation( - source, - expected, - (s, d) => ImageSharp.PixelFormats.Rgba32.PixelOperations.ToVector4SimdAligned(s, d.GetSpan(), 64) - ); - } - - - // [Fact] // Profiling benchmark - enable manually! -#pragma warning disable xUnit1013 // Public method should be marked as test + [Fact(Skip = SkipProfilingBenchmarks)] public void Benchmark_ToVector4() -#pragma warning restore xUnit1013 // Public method should be marked as test { int times = 200000; int count = 1024; @@ -73,13 +56,10 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public class Argb32 : PixelOperationsTests { - // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: public Argb32(ITestOutputHelper output) : base(output) { } - - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; } [Theory] @@ -110,7 +90,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { } - public static TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + public static TheoryData ArraySizesData => new TheoryData { 0, 1, 2, 7, 16, 1111 }; private static PixelOperations Operations => PixelOperations.Instance; From f1e88865915d346802c0b2a252ba73679e203ace Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 15 Oct 2018 16:01:51 -0700 Subject: [PATCH 158/381] 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 df87a68555b480e58e886e6f9d2513db29c8d5fd Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 16 Oct 2018 01:02:39 +0200 Subject: [PATCH 159/381] BulkConvertNormalizedFloatToByteClampOverflows --- .../SimdUtils.ExtendedIntrinsics.cs | 66 +++++++++++++++++-- .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 18 +++++ 2 files changed, 79 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs index ec52b90eff..97f364a109 100644 --- a/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs @@ -24,6 +24,9 @@ namespace SixLabors.ImageSharp false; #endif + /// + /// A variant of , which is faster on new .NET runtime. + /// // ReSharper disable once MemberHidesStaticFromOuterClass internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { @@ -37,7 +40,7 @@ namespace SixLabors.ImageSharp ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); - var scale = new Vector(1f / 255f); + const float Scale = 1f / 255f; for (int i = 0; i < n; i++) { @@ -47,10 +50,10 @@ namespace SixLabors.ImageSharp Vector.Widen(s0, out Vector w0, out Vector w1); Vector.Widen(s1, out Vector w2, out Vector w3); - Vector f0 = Vector.ConvertToSingle(w0) * scale; - Vector f1 = Vector.ConvertToSingle(w1) * scale; - Vector f2 = Vector.ConvertToSingle(w2) * scale; - Vector f3 = Vector.ConvertToSingle(w3) * scale; + Vector f0 = Vector.ConvertToSingle(w0) * Scale; + Vector f1 = Vector.ConvertToSingle(w1) * Scale; + Vector f2 = Vector.ConvertToSingle(w2) * Scale; + Vector f3 = Vector.ConvertToSingle(w3) * Scale; ref Vector d = ref Unsafe.Add(ref destBase, i * 4); d = f0; @@ -59,6 +62,59 @@ namespace SixLabors.ImageSharp Unsafe.Add(ref d, 3) = f3; } } + + /// + /// A variant of , which is faster on new .NET runtime. + /// + // ReSharper disable once MemberHidesStaticFromOuterClass + internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) + { + Guard.IsTrue( + dest.Length % Vector.Count == 0, + nameof(source), + "dest.Length should be divisable by Vector.Count!"); + + int n = dest.Length / Vector.Count; + + ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + + for (int i = 0; i < n; i++) + { + ref Vector s = ref Unsafe.Add(ref sourceBase, i * 4); + + Vector f0 = s; + f0 = Clamp(f0); + + Vector f1 = Unsafe.Add(ref s, 1); + f1 = Clamp(f1); + + Vector f2 = Unsafe.Add(ref s, 2); + f2 = Clamp(f2); + + Vector f3 = Unsafe.Add(ref s, 3); + f3 = Clamp(f3); + + Vector w0 = Vector.ConvertToUInt32(f0 * 255f); + Vector w1 = Vector.ConvertToUInt32(f1 * 255f); + Vector w2 = Vector.ConvertToUInt32(f2 * 255f); + Vector w3 = Vector.ConvertToUInt32(f3 * 255f); + + Vector u0 = Vector.Narrow(w0, w1); + Vector u1 = Vector.Narrow(w2, w3); + + Vector b = Vector.Narrow(u0, u1); + + Unsafe.Add(ref destBase, i) = b; + } + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector Clamp(Vector x) + { + return Vector.Min(Vector.Max(x, Vector.Zero), Vector.One); + } } } } diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index 0488dd5e15..4b23ca30f1 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -226,6 +226,24 @@ namespace SixLabors.ImageSharp.Tests.Common Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); } + [Theory] + [InlineData(1, 0)] + [InlineData(2, 32)] + [InlineData(3, 128)] + public void ExtendedIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int seed, int count) + { + float[] orig = new Random(seed).GenerateRandomRoundedFloatArray(count, -50, 444); + float[] normalized = orig.Select(f => f / 255f).ToArray(); + + byte[] dest = new byte[count]; + + SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(normalized, dest); + + byte[] expected = orig.Select(f => (byte)Clamp255(f)).ToArray(); + + Assert.Equal(expected, dest); + } + [Theory] [InlineData(0)] [InlineData(7)] From d0b16334861bda1fd9b6b06776a419ad48d11574 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 15 Oct 2018 16:04:19 -0700 Subject: [PATCH 160/381] 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 741b7dd70f349b26cc92569b9844ee636e6e7143 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 15 Oct 2018 16:06:41 -0700 Subject: [PATCH 161/381] 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 eedc89e588e89257564c78f1999f5ce47d957734 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 15 Oct 2018 16:07:07 -0700 Subject: [PATCH 162/381] 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 b8b411bb716664d840d08f96759cec91f4f471d4 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 16 Oct 2018 01:13:43 +0200 Subject: [PATCH 163/381] disappointing benchmark results --- .../SimdUtils.ExtendedIntrinsics.cs | 5 +- .../Color/Bulk/PackFromVector4.cs | 48 +++++++++++++++++-- .../Color/Bulk/ToVector4.cs | 6 +-- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs index 97f364a109..90048ca9b4 100644 --- a/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs @@ -66,6 +66,10 @@ namespace SixLabors.ImageSharp /// /// A variant of , which is faster on new .NET runtime. /// + /// + /// It does NOT worth yet to utilize this method (2018 Oct). + /// See benchmark results for the "PackFromVector4_Rgba32" benchmark! + /// // ReSharper disable once MemberHidesStaticFromOuterClass internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) { @@ -107,7 +111,6 @@ namespace SixLabors.ImageSharp Unsafe.Add(ref destBase, i) = b; } - } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index bdae7d0655..4bf98e5ceb 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -3,6 +3,7 @@ // ReSharper disable InconsistentNaming +using System; using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; @@ -19,9 +20,9 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk public abstract class PackFromVector4 where TPixel : struct, IPixel { - private IMemoryOwner source; + protected IMemoryOwner source; - private IMemoryOwner destination; + protected IMemoryOwner destination; [Params( //64, @@ -42,7 +43,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.source.Dispose(); } - [Benchmark(Baseline = true)] + [Benchmark] public void PerElement() { ref Vector4 s = ref MemoryMarshal.GetReference(this.source.GetSpan()); @@ -54,7 +55,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - [Benchmark] + [Benchmark(Baseline = true)] public void CommonBulk() { new PixelOperations().PackFromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); @@ -69,6 +70,45 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk public class PackFromVector4_Rgba32 : PackFromVector4 { + //[Benchmark] + public void BulkConvertNormalizedFloatToByteClampOverflows() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); + } + + [Benchmark] + public void ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); + } + // RESULTS: + // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 + // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores + // Frequency=2742187 Hz, Resolution=364.6724 ns, Timer=TSC + // .NET Core SDK=2.1.400-preview-009063 + // [Host] : .NET Core 2.1.1 (CoreCLR 4.6.26606.02, CoreFX 4.6.26606.05), 64bit RyuJIT + // Job-XIFINS : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 + // Job-RTQZPN : .NET Core 2.1.1 (CoreCLR 4.6.26606.02, CoreFX 4.6.26606.05), 64bit RyuJIT + // + // LaunchCount=1 TargetCount=3 WarmupCount=3 + // + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Allocated | + // ----------------------------------------------------------------- |-------- |------ |----------:|-----------:|----------:|-------:|---------:|----------:| + // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 2048 | 3.755 us | 0.8959 us | 0.0506 us | 0.22 | 0.00 | 0 B | + // PerElement | Clr | 2048 | 17.387 us | 15.1569 us | 0.8564 us | 1.02 | 0.04 | 0 B | + // CommonBulk | Clr | 2048 | 17.121 us | 0.7634 us | 0.0431 us | 1.00 | 0.00 | 24 B | + // OptimizedBulk | Clr | 2048 | 4.018 us | 0.3858 us | 0.0218 us | 0.23 | 0.00 | 0 B | + // | | | | | | | | | + // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Core | 2048 | 22.232 us | 1.6154 us | 0.0913 us | 1.31 | 0.04 | 0 B | + // PerElement | Core | 2048 | 16.741 us | 2.9254 us | 0.1653 us | 0.98 | 0.03 | 0 B | + // CommonBulk | Core | 2048 | 17.022 us | 11.4894 us | 0.6492 us | 1.00 | 0.00 | 24 B | + // OptimizedBulk | Core | 2048 | 3.707 us | 0.1500 us | 0.0085 us | 0.22 | 0.01 | 0 B | } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 3ea256e85a..39c1fbd474 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk { } - //[Benchmark] + [Benchmark] public void BulkConvertByteToNormalizedFloat() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); @@ -89,12 +89,12 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark] - public void BulkConvertByteToNormalizedFloatFast() + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - SimdUtils.BulkConvertByteToNormalizedFloatWithExtendedIntrinsics(sBytes, dFloats); + SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats); } } From fd9e8dc7dec6f6e10bbbd616ef1b4d27c7dffd8f Mon Sep 17 00:00:00 2001 From: j0rn Date: Tue, 16 Oct 2018 10:23:03 +0200 Subject: [PATCH 164/381] 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()); - } -} From 778895b44beb1b20aa257abb415e6a5a009a0994 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 16 Oct 2018 13:41:58 +0100 Subject: [PATCH 165/381] Use FormattableString --- src/ImageSharp/PixelFormats/Bgr565.cs | 2 +- src/ImageSharp/PixelFormats/Bgra4444.cs | 2 +- src/ImageSharp/PixelFormats/Bgra5551.cs | 2 +- src/ImageSharp/PixelFormats/Byte4.cs | 2 +- src/ImageSharp/PixelFormats/HalfSingle.cs | 3 ++- src/ImageSharp/PixelFormats/HalfVector2.cs | 3 ++- src/ImageSharp/PixelFormats/HalfVector4.cs | 3 ++- src/ImageSharp/PixelFormats/NormalizedByte2.cs | 2 +- src/ImageSharp/PixelFormats/NormalizedByte4.cs | 2 +- src/ImageSharp/PixelFormats/NormalizedShort2.cs | 2 +- src/ImageSharp/PixelFormats/NormalizedShort4.cs | 2 +- src/ImageSharp/PixelFormats/Rg32.cs | 2 +- src/ImageSharp/PixelFormats/Rgba1010102.cs | 6 +++++- src/ImageSharp/PixelFormats/RgbaVector.cs | 3 ++- src/ImageSharp/PixelFormats/Short2.cs | 2 +- src/ImageSharp/PixelFormats/Short4.cs | 2 +- 16 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/ImageSharp/PixelFormats/Bgr565.cs b/src/ImageSharp/PixelFormats/Bgr565.cs index 454f458b12..04af6ef0f1 100644 --- a/src/ImageSharp/PixelFormats/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/Bgr565.cs @@ -148,7 +148,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector3(); - return $"Bgr565({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##})"; + return FormattableString.Invariant($"Bgr565({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##})"); } /// diff --git a/src/ImageSharp/PixelFormats/Bgra4444.cs b/src/ImageSharp/PixelFormats/Bgra4444.cs index 08484eba8d..db1c8f865a 100644 --- a/src/ImageSharp/PixelFormats/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/Bgra4444.cs @@ -137,7 +137,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector4(); - return $"Bgra4444({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})"; + return FormattableString.Invariant($"Bgra4444({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})"); } /// diff --git a/src/ImageSharp/PixelFormats/Bgra5551.cs b/src/ImageSharp/PixelFormats/Bgra5551.cs index df0a467301..5d9003cdd3 100644 --- a/src/ImageSharp/PixelFormats/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/Bgra5551.cs @@ -138,7 +138,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector4(); - return $"Bgra5551({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})"; + return FormattableString.Invariant($"Bgra5551({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})"); } /// diff --git a/src/ImageSharp/PixelFormats/Byte4.cs b/src/ImageSharp/PixelFormats/Byte4.cs index 34546e0271..230c31c5c3 100644 --- a/src/ImageSharp/PixelFormats/Byte4.cs +++ b/src/ImageSharp/PixelFormats/Byte4.cs @@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector4(); - return $"Bgra5551({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"; + return FormattableString.Invariant($"Bgra5551({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } /// diff --git a/src/ImageSharp/PixelFormats/HalfSingle.cs b/src/ImageSharp/PixelFormats/HalfSingle.cs index 78edc9a08e..bef4a5dd9b 100644 --- a/src/ImageSharp/PixelFormats/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/HalfSingle.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Numerics; using System.Runtime.CompilerServices; @@ -130,7 +131,7 @@ namespace SixLabors.ImageSharp.PixelFormats public bool Equals(HalfSingle other) => this.PackedValue.Equals(other.PackedValue); /// - public override string ToString() => $"HalfSingle({this.ToSingle():#0.##})"; + public override string ToString() => FormattableString.Invariant($"HalfSingle({this.ToSingle():#0.##})"); /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/HalfVector2.cs b/src/ImageSharp/PixelFormats/HalfVector2.cs index e3777bc2fb..5bd9924c53 100644 --- a/src/ImageSharp/PixelFormats/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/HalfVector2.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Numerics; using System.Runtime.CompilerServices; @@ -150,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector2(); - return $"HalfVector2({vector.X:#0.##}, {vector.Y:#0.##})"; + return FormattableString.Invariant($"HalfVector2({vector.X:#0.##}, {vector.Y:#0.##})"); } /// diff --git a/src/ImageSharp/PixelFormats/HalfVector4.cs b/src/ImageSharp/PixelFormats/HalfVector4.cs index 079c3ee383..2e487ef985 100644 --- a/src/ImageSharp/PixelFormats/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/HalfVector4.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Numerics; using System.Runtime.CompilerServices; @@ -145,7 +146,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector4(); - return $"HalfVector4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"; + return FormattableString.Invariant($"HalfVector4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } /// diff --git a/src/ImageSharp/PixelFormats/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/NormalizedByte2.cs index 3eaa69c03e..219ec87630 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte2.cs @@ -161,7 +161,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector2(); - return $"NormalizedByte2({vector.X:#0.##}, {vector.Y:#0.##})"; + return FormattableString.Invariant($"NormalizedByte2({vector.X:#0.##}, {vector.Y:#0.##})"); } [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/NormalizedByte4.cs index e0e3e65020..d5795cb4bd 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte4.cs @@ -153,7 +153,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector4(); - return $"NormalizedByte4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"; + return FormattableString.Invariant($"NormalizedByte4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/NormalizedShort2.cs index 0aa5736379..34e752496a 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort2.cs @@ -163,7 +163,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector2(); - return $"NormalizedShort2({vector.X:#0.##}, {vector.Y:#0.##})"; + return FormattableString.Invariant($"NormalizedShort2({vector.X:#0.##}, {vector.Y:#0.##})"); } [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/NormalizedShort4.cs index 577e901544..6fda84bc2e 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort4.cs @@ -155,7 +155,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector4(); - return $"NormalizedShort4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"; + return FormattableString.Invariant($"NormalizedShort4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Rg32.cs b/src/ImageSharp/PixelFormats/Rg32.cs index 02c294b4ff..0831f6524e 100644 --- a/src/ImageSharp/PixelFormats/Rg32.cs +++ b/src/ImageSharp/PixelFormats/Rg32.cs @@ -140,7 +140,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector2(); - return $"Rg32({vector.X:#0.##}, {vector.Y:#0.##})"; + return FormattableString.Invariant($"Rg32({vector.X:#0.##}, {vector.Y:#0.##})"); } /// diff --git a/src/ImageSharp/PixelFormats/Rgba1010102.cs b/src/ImageSharp/PixelFormats/Rgba1010102.cs index 86b639e229..14265b54e9 100644 --- a/src/ImageSharp/PixelFormats/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/Rgba1010102.cs @@ -135,7 +135,11 @@ namespace SixLabors.ImageSharp.PixelFormats public bool Equals(Rgba1010102 other) => this.PackedValue == other.PackedValue; /// - public override string ToString() => this.ToVector4().ToString(); + public override string ToString() + { + var vector = this.ToVector4(); + return FormattableString.Invariant($"Rgba1010102({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/RgbaVector.cs b/src/ImageSharp/PixelFormats/RgbaVector.cs index b5ccf8aedc..b2a3dc578e 100644 --- a/src/ImageSharp/PixelFormats/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/RgbaVector.cs @@ -1,6 +1,7 @@ // 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; @@ -189,7 +190,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector4(); - return $"RgbaVector({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##}, {this.A:#0.##})"; + return FormattableString.Invariant($"RgbaVector({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##}, {this.A:#0.##})"); } /// diff --git a/src/ImageSharp/PixelFormats/Short2.cs b/src/ImageSharp/PixelFormats/Short2.cs index db29b401ed..81df3ef7b9 100644 --- a/src/ImageSharp/PixelFormats/Short2.cs +++ b/src/ImageSharp/PixelFormats/Short2.cs @@ -162,7 +162,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector2(); - return $"Short2({vector.X:#0.##}, {vector.Y:#0.##})"; + return FormattableString.Invariant($"Short2({vector.X:#0.##}, {vector.Y:#0.##})"); } [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Short4.cs b/src/ImageSharp/PixelFormats/Short4.cs index 6d6e5f0845..48bd01d6e1 100644 --- a/src/ImageSharp/PixelFormats/Short4.cs +++ b/src/ImageSharp/PixelFormats/Short4.cs @@ -162,7 +162,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector4(); - return $"Short4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"; + return FormattableString.Invariant($"Short4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } [MethodImpl(InliningOptions.ShortMethod)] From 1daa463fd261df0a952766d39c3bb6e9e5d626f2 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 16 Oct 2018 14:26:40 +0100 Subject: [PATCH 166/381] Use new IPixel API --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 24 +++------ src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 34 +++++++++---- .../Formats/Png/PngScanlineProcessor.cs | 51 +++++-------------- 3 files changed, 45 insertions(+), 64 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 71852acddd..dabab651d0 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -219,8 +219,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp where TPixel : struct, IPixel { TPixel color = default; - var rgba = new Rgba32(0, 0, 0, 255); - using (Buffer2D buffer = this.memoryAllocator.Allocate2D(width, height, AllocationOptions.Clean)) { this.UncompressRle8(width, buffer.GetSpan()); @@ -233,8 +231,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp for (int x = 0; x < width; x++) { - rgba.Bgr = Unsafe.As(ref colors[bufferRow[x] * 4]); - color.PackFromRgba32(rgba); + color.PackFromBgr24(Unsafe.As(ref colors[bufferRow[x] * 4])); pixelRow[x] = color; } } @@ -352,8 +349,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp using (IManagedByteBuffer row = this.memoryAllocator.AllocateManagedByteBuffer(arrayWidth + padding, AllocationOptions.Clean)) { TPixel color = default; - var rgba = new Rgba32(0, 0, 0, 255); - Span rowSpan = row.GetSpan(); for (int y = 0; y < height; y++) @@ -363,7 +358,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp int offset = 0; Span pixelRow = pixels.GetRowSpan(newY); - // TODO: Could use PixelOperations here! for (int x = 0; x < arrayWidth; x++) { int colOffset = x * ppb; @@ -371,9 +365,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp { int colorIndex = ((rowSpan[offset] >> (8 - bits - (shift * bits))) & mask) * 4; - // Stored in b-> g-> r order. - rgba.Bgr = Unsafe.As(ref colors[colorIndex]); - color.PackFromRgba32(rgba); + color.PackFromBgr24(Unsafe.As(ref colors[colorIndex])); pixelRow[newX] = color; } @@ -397,7 +389,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp int padding = CalculatePadding(width, 2); int stride = (width * 2) + padding; TPixel color = default; - var rgba = new Rgba32(0, 0, 0, 255); using (IManagedByteBuffer buffer = this.memoryAllocator.AllocateManagedByteBuffer(stride)) { @@ -412,11 +403,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp { short temp = BitConverter.ToInt16(buffer.Array, offset); - rgba.R = GetBytesFrom5BitValue((temp & Rgb16RMask) >> 10); - rgba.G = GetBytesFrom5BitValue((temp & Rgb16GMask) >> 5); - rgba.B = GetBytesFrom5BitValue(temp & Rgb16BMask); + var rgb = new Rgb24( + GetBytesFrom5BitValue((temp & Rgb16RMask) >> 10), + GetBytesFrom5BitValue((temp & Rgb16GMask) >> 5), + GetBytesFrom5BitValue(temp & Rgb16BMask)); - color.PackFromRgba32(rgba); + color.PackFromRgb24(rgb); pixelRow[x] = color; offset += 2; } @@ -537,7 +529,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.metaData = meta; short bitsPerPixel = this.infoHeader.BitsPerPixel; - var bmpMetaData = this.metaData.GetFormatMetaData(BmpFormat.Instance); + BmpMetaData bmpMetaData = this.metaData.GetFormatMetaData(BmpFormat.Instance); // We can only encode at these bit rates so far. if (bitsPerPixel.Equals((short)BmpBitsPerPixel.Pixel24) diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 207f126f9e..155e6484f7 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -481,22 +481,36 @@ namespace SixLabors.ImageSharp.Formats.Gif } ref TPixel rowRef = ref MemoryMarshal.GetReference(imageFrame.GetPixelRowSpan(writeY)); - var rgba = new Rgba32(0, 0, 0, 255); + bool transFlag = this.graphicsControlExtension.TransparencyFlag; - // #403 The left + width value can be larger than the image width - for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++) + if (!transFlag) { - int index = Unsafe.Add(ref indicesRef, i); - - if (!this.graphicsControlExtension.TransparencyFlag - || this.graphicsControlExtension.TransparencyIndex != index) + // #403 The left + width value can be larger than the image width + for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++) { + int index = Unsafe.Add(ref indicesRef, i); ref TPixel pixel = ref Unsafe.Add(ref rowRef, x); - rgba.Rgb = colorTable[index]; - pixel.PackFromRgba32(rgba); + Rgb24 rgb = colorTable[index]; + pixel.PackFromRgb24(rgb); + + i++; } + } + else + { + byte transIndex = this.graphicsControlExtension.TransparencyIndex; + for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++) + { + int index = Unsafe.Add(ref indicesRef, i); + if (transIndex != index) + { + ref TPixel pixel = ref Unsafe.Add(ref rowRef, x); + Rgb24 rgb = colorTable[index]; + pixel.PackFromRgb24(rgb); + } - i++; + i++; + } } } diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index 6c81ba76c2..92c76a3fa2 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -32,30 +32,19 @@ namespace SixLabors.ImageSharp.Formats.Png { 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); + pixel.PackFromGray16(new Gray16(luminance)); 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); + pixel.PackFromGray8(new Gray8(luminance)); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -115,30 +104,19 @@ namespace SixLabors.ImageSharp.Formats.Png { 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); + pixel.PackFromGray16(new Gray16(luminance)); 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); + pixel.PackFromGray8(new Gray8(luminance)); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -309,14 +287,12 @@ namespace SixLabors.ImageSharp.Formats.Png } 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); + Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index); - pixel.PackFromRgba32(rgba); + pixel.PackFromRgb24(rgb); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -356,13 +332,12 @@ namespace SixLabors.ImageSharp.Formats.Png } 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); + Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index); - pixel.PackFromRgba32(rgba); + pixel.PackFromRgb24(rgb); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -509,14 +484,14 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - var rgba = new Rgba32(0, 0, 0, byte.MaxValue); + Rgb24 rgb = default; for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += bytesPerPixel) { - rgba.R = Unsafe.Add(ref scanlineSpanRef, o); - rgba.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample); - rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); + rgb.R = Unsafe.Add(ref scanlineSpanRef, o); + rgb.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample); + rgb.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); - pixel.PackFromRgba32(rgba); + pixel.PackFromRgb24(rgb); Unsafe.Add(ref rowSpanRef, x) = pixel; } } From a4714207e03a0a8f92d0ee95751eb8693ef3a14e Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 17 Oct 2018 23:39:29 +0200 Subject: [PATCH 167/381] todo notes --- .../Common/Extensions/SimdUtils.ExtendedIntrinsics.cs | 1 + tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs index 90048ca9b4..fba54b033a 100644 --- a/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs @@ -69,6 +69,7 @@ namespace SixLabors.ImageSharp /// /// It does NOT worth yet to utilize this method (2018 Oct). /// See benchmark results for the "PackFromVector4_Rgba32" benchmark! + /// TODO: Check again later! /// // ReSharper disable once MemberHidesStaticFromOuterClass internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index 4bf98e5ceb..fb505ddcbd 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -88,7 +88,9 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); } + // TODO: Check again later! // RESULTS: + // // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores // Frequency=2742187 Hz, Resolution=364.6724 ns, Timer=TSC From fbde4f32fd501542d99e59c639d3f1154174240e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 18 Oct 2018 17:04:41 +0100 Subject: [PATCH 168/381] Use scaled luminance trns comparison. --- .../Formats/Png/PngScanlineProcessor.cs | 6 ++++-- .../Formats/Png/PngDecoderTests.cs | 3 ++- tests/ImageSharp.Tests/TestImages.cs | 1 + tests/Images/Input/Png/gray-1-trns.png | Bin 0 -> 366 bytes 4 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 tests/Images/Input/Png/gray-1-trns.png diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index 6c81ba76c2..5ea25e72d4 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -80,6 +80,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { + byte scaledLuminanceTrans = (byte)(luminanceTrans * scaleFactor); Rgba32 rgba32 = default; for (int x = 0; x < header.Width; x++) { @@ -87,7 +88,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba32.R = luminance; rgba32.G = luminance; rgba32.B = luminance; - rgba32.A = luminance.Equals(luminanceTrans) ? byte.MinValue : byte.MaxValue; + rgba32.A = luminance.Equals(scaledLuminanceTrans) ? byte.MinValue : byte.MaxValue; pixel.PackFromRgba32(rgba32); Unsafe.Add(ref rowSpanRef, x) = pixel; @@ -163,6 +164,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { + byte scaledLuminanceTrans = (byte)(luminanceTrans * scaleFactor); Rgba32 rgba32 = default; for (int x = pixelOffset; x < header.Width; x += increment) { @@ -170,7 +172,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba32.R = luminance; rgba32.G = luminance; rgba32.B = luminance; - rgba32.A = luminance.Equals(luminanceTrans) ? byte.MinValue : byte.MaxValue; + rgba32.A = luminance.Equals(scaledLuminanceTrans) ? byte.MinValue : byte.MaxValue; pixel.PackFromRgba32(rgba32); Unsafe.Add(ref rowSpanRef, x) = pixel; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 54f3e397c3..f51f9b6c5c 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -40,7 +40,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png TestImages.Png.VimImage2, TestImages.Png.Rgb24BppTrans, - TestImages.Png.GrayAlpha8Bit + TestImages.Png.GrayAlpha8Bit, + TestImages.Png.Gray1BitTrans }; public static readonly string[] TestImages48Bpp = diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index fdf586c430..758f256345 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -45,6 +45,7 @@ namespace SixLabors.ImageSharp.Tests public const string Kaboom = "Png/kaboom.png"; public const string PDSrc = "Png/pd-source.png"; public const string PDDest = "Png/pd-dest.png"; + public const string Gray1BitTrans = "Png/gray-1-trns.png"; // Filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html public const string Filter0 = "Png/filter0.png"; diff --git a/tests/Images/Input/Png/gray-1-trns.png b/tests/Images/Input/Png/gray-1-trns.png new file mode 100644 index 0000000000000000000000000000000000000000..99b288d52666f930ba760226e0687fd16c18e967 GIT binary patch literal 366 zcmeAS@N?(olHy`uVBq!ia0y~yVAN$`VCrH73NSci8gu|Drjj7PU~)y|GZ}kOL3P1p|(h`kCj~HI)TOcnDs2`|;Yn&D&2d zc^7STeg3AM*X9_!nQ1%k9^2s!>o-0rI$*$ac*DU6>$&Pc+F)ADDv7qN_JtVTp*E8bj_RaPgn@lz~JfX=d#Wzp$Pzp C@PiTn literal 0 HcmV?d00001 From 9b196316d687d40e2a1d735eb58cb8e25000aceb Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 18 Oct 2018 22:45:39 +0200 Subject: [PATCH 169/381] common fixtures for PixelConversion* benchmarks --- .../General/PixelConversion/ITestPixel.cs | 24 ++++++ .../PixelConversion_ConvertFromRgba32.cs | 81 ++----------------- .../PixelConversion_ConvertFromVector4.cs | 53 ++++-------- .../PixelConversion_ConvertToRgba32.cs | 59 ++------------ .../General/PixelConversion/TestArgb.cs | 74 +++++++++++++++++ .../General/PixelConversion/TestRgba.cs | 57 +++++++++++++ 6 files changed, 181 insertions(+), 167 deletions(-) create mode 100644 tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs rename tests/ImageSharp.Benchmarks/General/{ => PixelConversion}/PixelConversion_ConvertFromRgba32.cs (66%) rename tests/ImageSharp.Benchmarks/General/{ => PixelConversion}/PixelConversion_ConvertFromVector4.cs (75%) rename tests/ImageSharp.Benchmarks/General/{ => PixelConversion}/PixelConversion_ConvertToRgba32.cs (68%) create mode 100644 tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs create mode 100644 tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs new file mode 100644 index 0000000000..ede617032f --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs @@ -0,0 +1,24 @@ +using System.Numerics; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + interface ITestPixel + where T : struct, ITestPixel + { + void FromRgba32(Rgba32 source); + + void FromRgba32(ref Rgba32 source); + + void FromBytes(byte r, byte g, byte b, byte a); + + void FromVector4(Vector4 source); + + void FromVector4(ref Vector4 source); + + Rgba32 ToRgba32(); + + void CopyToRgba32(ref Rgba32 dest); + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs similarity index 66% rename from tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromRgba32.cs rename to tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs index f5bd135e12..046c7dd90c 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs @@ -1,86 +1,15 @@ // ReSharper disable InconsistentNaming -using SixLabors.ImageSharp.PixelFormats; +using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; +using BenchmarkDotNet.Attributes; - using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.PixelFormats; +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ public class PixelConversion_ConvertFromRgba32 { - interface ITestPixel - where T : struct, ITestPixel - { - void FromRgba32(Rgba32 source); - - void FromRgba32(ref Rgba32 source); - - void FromBytes(byte r, byte g, byte b, byte a); - } - - [StructLayout(LayoutKind.Sequential)] - struct TestArgb : ITestPixel - { - private byte a, r, g, b; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(Rgba32 p) - { - this.r = p.R; - this.g = p.G; - this.b = p.B; - this.a = p.A; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(ref Rgba32 p) - { - this.r = p.R; - this.g = p.G; - this.b = p.B; - this.a = p.A; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromBytes(byte r, byte g, byte b, byte a) - { - this.r = r; - this.g = g; - this.b = b; - this.a = a; - } - } - - [StructLayout(LayoutKind.Sequential)] - struct TestRgba : ITestPixel - { - private byte r, g, b, a; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(Rgba32 source) - { - this = Unsafe.As(ref source); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(ref Rgba32 source) - { - this = Unsafe.As(ref source); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromBytes(byte r, byte g, byte b, byte a) - { - this.r = r; - this.g = g; - this.b = b; - this.a = a; - } - } - struct ConversionRunner where T : struct, ITestPixel { diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromVector4.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs similarity index 75% rename from tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromVector4.cs rename to tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs index 5b059e2e65..30af857b1d 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs @@ -1,46 +1,17 @@ // ReSharper disable InconsistentNaming -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System.Numerics; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - - using BenchmarkDotNet.Attributes; - - public class PixelConversion_ConvertFromVector4 - { - interface ITestPixel - where T : struct, ITestPixel - { - void FromVector4(Vector4 source); - - void FromVector4(ref Vector4 source); - } - [StructLayout(LayoutKind.Sequential)] - struct TestArgb : ITestPixel - { - private byte a, r, g, b; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromVector4(Vector4 p) - { - this.r = (byte)p.X; - this.g = (byte)p.Y; - this.b = (byte)p.Z; - this.a = (byte)p.W; - } +using BenchmarkDotNet.Attributes; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromVector4(ref Vector4 p) - { - this.r = (byte)p.X; - this.g = (byte)p.Y; - this.b = (byte)p.Z; - this.a = (byte)p.W; - } - } +using SixLabors.ImageSharp.PixelFormats; +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + public class PixelConversion_ConvertFromVector4 + { [StructLayout(LayoutKind.Sequential)] struct TestRgbaVector : ITestPixel { @@ -57,6 +28,12 @@ namespace SixLabors.ImageSharp.Benchmarks.General { this.v = p; } + + public void FromRgba32(Rgba32 source) => throw new System.NotImplementedException(); + public void FromRgba32(ref Rgba32 source) => throw new System.NotImplementedException(); + public void FromBytes(byte r, byte g, byte b, byte a) => throw new System.NotImplementedException(); + public Rgba32 ToRgba32() => throw new System.NotImplementedException(); + public void CopyToRgba32(ref Rgba32 dest) => throw new System.NotImplementedException(); } struct ConversionRunner diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertToRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs similarity index 68% rename from tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertToRgba32.cs rename to tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs index 5656904fe0..89b4031a85 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertToRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs @@ -1,14 +1,14 @@ // ReSharper disable InconsistentNaming -using SixLabors.ImageSharp.PixelFormats; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; +using BenchmarkDotNet.Attributes; - using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.PixelFormats; +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ /// /// When implementing TPixel --> Rgba32 style conversions on IPixel, should which API should we prefer? /// 1. Rgba32 ToRgba32(); @@ -18,53 +18,6 @@ namespace SixLabors.ImageSharp.Benchmarks.General /// public class PixelConversion_ConvertToRgba32 { - interface ITestPixel - where T : struct, ITestPixel - { - Rgba32 ToRgba32(); - - void CopyToRgba32(ref Rgba32 dest); - } - - [StructLayout(LayoutKind.Sequential)] - struct TestArgb : ITestPixel - { - private byte a, r, g, b; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Rgba32 ToRgba32() - { - return new Rgba32(this.r, this.g, this.b, this.a); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyToRgba32(ref Rgba32 dest) - { - dest.R = this.r; - dest.G = this.g; - dest.B = this.b; - dest.A = this.a; - } - } - - [StructLayout(LayoutKind.Sequential)] - struct TestRgba : ITestPixel - { - private byte r, g, b, a; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Rgba32 ToRgba32() - { - return Unsafe.As(ref this); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyToRgba32(ref Rgba32 dest) - { - dest = Unsafe.As(ref this); - } - } - struct ConversionRunner where T : struct, ITestPixel { diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs new file mode 100644 index 0000000000..ddac1d1052 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs @@ -0,0 +1,74 @@ +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + [StructLayout(LayoutKind.Sequential)] + struct TestArgb : ITestPixel + { + private byte a, r, g, b; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(Rgba32 p) + { + this.r = p.R; + this.g = p.G; + this.b = p.B; + this.a = p.A; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(ref Rgba32 p) + { + this.r = p.R; + this.g = p.G; + this.b = p.B; + this.a = p.A; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromBytes(byte r, byte g, byte b, byte a) + { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromVector4(Vector4 p) + { + this.r = (byte)p.X; + this.g = (byte)p.Y; + this.b = (byte)p.Z; + this.a = (byte)p.W; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromVector4(ref Vector4 p) + { + this.r = (byte)p.X; + this.g = (byte)p.Y; + this.b = (byte)p.Z; + this.a = (byte)p.W; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Rgba32 ToRgba32() + { + return new Rgba32(this.r, this.g, this.b, this.a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyToRgba32(ref Rgba32 dest) + { + dest.R = this.r; + dest.G = this.g; + dest.B = this.b; + dest.A = this.a; + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs new file mode 100644 index 0000000000..b06e84063f --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs @@ -0,0 +1,57 @@ +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + [StructLayout(LayoutKind.Sequential)] + struct TestRgba : ITestPixel + { + private byte r, g, b, a; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(Rgba32 source) + { + this = Unsafe.As(ref source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(ref Rgba32 source) + { + this = Unsafe.As(ref source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromBytes(byte r, byte g, byte b, byte a) + { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + public void FromVector4(Vector4 source) + { + throw new System.NotImplementedException(); + } + + public void FromVector4(ref Vector4 source) + { + throw new System.NotImplementedException(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Rgba32 ToRgba32() + { + return Unsafe.As(ref this); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyToRgba32(ref Rgba32 dest) + { + dest = Unsafe.As(ref this); + } + } +} \ No newline at end of file From 3051d718a370aa5c33622461729d33e491eb3d99 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 18 Oct 2018 22:56:02 +0200 Subject: [PATCH 170/381] PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation --- ...vertToRgba32_AsPartOfCompositeOperation.cs | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs new file mode 100644 index 0000000000..a27f7c3a5d --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs @@ -0,0 +1,113 @@ +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + public class PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation + { + struct ConversionRunner + where T : struct, ITestPixel + { + private T[] source; + + private Rgba32[] dest; + + public ConversionRunner(int count) + { + this.source = new T[count]; + this.dest = new Rgba32[count]; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunRetvalConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Rgba32 destBaseRef = ref this.dest[0]; + + Rgba32 temp; + + for (int i = 0; i < count; i++) + { + temp = Unsafe.Add(ref sourceBaseRef, i).ToRgba32(); + + // manipulate pixel before saving to dest buffer: + temp.A = 0; + + Unsafe.Add(ref destBaseRef, i) = temp; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunCopyToConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Rgba32 destBaseRef = ref this.dest[0]; + + Rgba32 temp = default; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref sourceBaseRef, i).CopyToRgba32(ref temp); + + // manipulate pixel before saving to dest buffer: + temp.A = 0; + + Unsafe.Add(ref destBaseRef, i) = temp; + } + } + } + + private ConversionRunner compatibleMemoryLayoutRunner; + + private ConversionRunner permutedRunner; + + [Params(128)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.compatibleMemoryLayoutRunner = new ConversionRunner(this.Count); + this.permutedRunner = new ConversionRunner(this.Count); + } + + [Benchmark(Baseline = true)] + public void CompatibleRetval() + { + this.compatibleMemoryLayoutRunner.RunRetvalConversion(); + } + + [Benchmark] + public void CompatibleCopyTo() + { + this.compatibleMemoryLayoutRunner.RunCopyToConversion(); + } + + [Benchmark] + public void PermutedRetval() + { + this.permutedRunner.RunRetvalConversion(); + } + + [Benchmark] + public void PermutedCopyTo() + { + this.permutedRunner.RunCopyToConversion(); + } + } + + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | + // ----------------- |------ |-----------:|----------:|----------:|-------:|---------:| + // CompatibleRetval | 128 | 210.1 ns | 0.8443 ns | 0.7484 ns | 1.00 | 0.00 | + // CompatibleCopyTo | 128 | 140.1 ns | 0.4297 ns | 0.4019 ns | 0.67 | 0.00 | + // PermutedRetval | 128 | 1,044.6 ns | 3.7901 ns | 3.3599 ns | 4.97 | 0.02 | + // PermutedCopyTo | 128 | 140.3 ns | 0.6495 ns | 0.5757 ns | 0.67 | 0.00 | +} \ No newline at end of file From 9ab574c63369b3c68372ed28a3175e6735f09316 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 18 Oct 2018 23:13:44 +0200 Subject: [PATCH 171/381] benchmarks for TPixel -> Vector4 conversion --- .../General/PixelConversion/ITestPixel.cs | 4 + .../PixelConversion_ConvertFromVector4.cs | 9 ++ .../PixelConversion_ConvertToRgba32.cs | 2 +- ...vertToRgba32_AsPartOfCompositeOperation.cs | 14 +-- .../PixelConversion_ConvertToVector4.cs | 83 ++++++++++++++++ ...ertToVector4_AsPartOfCompositeOperation.cs | 95 +++++++++++++++++++ .../General/PixelConversion/TestArgb.cs | 15 +++ .../General/PixelConversion/TestRgba.cs | 15 +++ 8 files changed, 229 insertions(+), 8 deletions(-) create mode 100644 tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs create mode 100644 tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs index ede617032f..b5f339fb37 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs @@ -20,5 +20,9 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion Rgba32 ToRgba32(); void CopyToRgba32(ref Rgba32 dest); + + Vector4 ToVector4(); + + void CopyToVector4(ref Vector4 dest); } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs index 30af857b1d..d0c8a3045c 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs @@ -29,6 +29,15 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion this.v = p; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToVector4() => this.v; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyToVector4(ref Vector4 dest) + { + dest = this.v; + } + public void FromRgba32(Rgba32 source) => throw new System.NotImplementedException(); public void FromRgba32(ref Rgba32 source) => throw new System.NotImplementedException(); public void FromBytes(byte r, byte g, byte b, byte a) => throw new System.NotImplementedException(); diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs index 89b4031a85..d205e1e63e 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion private ConversionRunner permutedRunner; - [Params(128)] + [Params(32)] public int Count { get; set; } [GlobalSetup] diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs index a27f7c3a5d..fff9ae9bc7 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion private ConversionRunner permutedRunner; - [Params(128)] + [Params(32)] public int Count { get; set; } [GlobalSetup] @@ -104,10 +104,10 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion } // RESULTS: - // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | - // ----------------- |------ |-----------:|----------:|----------:|-------:|---------:| - // CompatibleRetval | 128 | 210.1 ns | 0.8443 ns | 0.7484 ns | 1.00 | 0.00 | - // CompatibleCopyTo | 128 | 140.1 ns | 0.4297 ns | 0.4019 ns | 0.67 | 0.00 | - // PermutedRetval | 128 | 1,044.6 ns | 3.7901 ns | 3.3599 ns | 4.97 | 0.02 | - // PermutedCopyTo | 128 | 140.3 ns | 0.6495 ns | 0.5757 ns | 0.67 | 0.00 | + // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | + // ----------------- |------ |----------:|----------:|----------:|-------:|---------:| + // CompatibleRetval | 32 | 53.05 ns | 0.1865 ns | 0.1557 ns | 1.00 | 0.00 | + // CompatibleCopyTo | 32 | 36.12 ns | 0.3596 ns | 0.3003 ns | 0.68 | 0.01 | + // PermutedRetval | 32 | 303.61 ns | 5.1697 ns | 4.8358 ns | 5.72 | 0.09 | + // PermutedCopyTo | 32 | 38.05 ns | 0.8053 ns | 1.2297 ns | 0.72 | 0.02 | } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs new file mode 100644 index 0000000000..29a1139912 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs @@ -0,0 +1,83 @@ +using System.Numerics; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + public class PixelConversion_ConvertToVector4 + { + struct ConversionRunner + where T : struct, ITestPixel + { + private T[] source; + + private Vector4[] dest; + + public ConversionRunner(int count) + { + this.source = new T[count]; + this.dest = new Vector4[count]; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunRetvalConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Vector4 destBaseRef = ref this.dest[0]; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref destBaseRef, i) = Unsafe.Add(ref sourceBaseRef, i).ToVector4(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunCopyToConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Vector4 destBaseRef = ref this.dest[0]; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref sourceBaseRef, i).CopyToVector4(ref Unsafe.Add(ref destBaseRef, i)); + } + } + } + + private ConversionRunner runner; + + [Params(32)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.runner = new ConversionRunner(this.Count); + } + + [Benchmark(Baseline = true)] + public void UseRetval() + { + this.runner.RunRetvalConversion(); + } + + [Benchmark] + public void UseCopyTo() + { + this.runner.RunCopyToConversion(); + } + + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | + // ---------- |------ |---------:|----------:|----------:|-------:| + // UseRetval | 32 | 94.99 ns | 1.1199 ns | 0.9352 ns | 1.00 | + // UseCopyTo | 32 | 59.47 ns | 0.6104 ns | 0.5710 ns | 0.63 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs new file mode 100644 index 0000000000..e5eb5c6cad --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs @@ -0,0 +1,95 @@ +using System.Numerics; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + public class PixelConversion_ConvertToVector4_AsPartOfCompositeOperation + { + struct ConversionRunner + where T : struct, ITestPixel + { + private T[] source; + + private Vector4[] dest; + + public ConversionRunner(int count) + { + this.source = new T[count]; + this.dest = new Vector4[count]; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunRetvalConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Vector4 destBaseRef = ref this.dest[0]; + + Vector4 temp; + + for (int i = 0; i < count; i++) + { + temp = Unsafe.Add(ref sourceBaseRef, i).ToVector4(); + + // manipulate pixel before saving to dest buffer: + temp.W = 0; + + Unsafe.Add(ref destBaseRef, i) = temp; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunCopyToConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Vector4 destBaseRef = ref this.dest[0]; + + Vector4 temp = default; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref sourceBaseRef, i).CopyToVector4(ref temp); + + // manipulate pixel before saving to dest buffer: + temp.W = 0; + + Unsafe.Add(ref destBaseRef, i) = temp; + } + } + } + + private ConversionRunner runner; + + [Params(32)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.runner = new ConversionRunner(this.Count); + } + + [Benchmark(Baseline = true)] + public void UseRetval() + { + this.runner.RunRetvalConversion(); + } + + [Benchmark] + public void UseCopyTo() + { + this.runner.RunCopyToConversion(); + } + + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | + // ---------- |------ |----------:|----------:|----------:|-------:| + // UseRetval | 32 | 100.35 ns | 0.4844 ns | 0.4532 ns | 1.00 | + // UseCopyTo | 32 | 53.95 ns | 0.1269 ns | 0.1125 ns | 0.54 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs index ddac1d1052..61a7df81d6 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs @@ -70,5 +70,20 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion dest.B = this.b; dest.A = this.a; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToVector4() + { + return new Vector4(this.r, this.g, this.b, this.a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyToVector4(ref Vector4 dest) + { + dest.X = this.r; + dest.Y = this.g; + dest.Z = this.b; + dest.W = this.a; + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs index b06e84063f..3da7fcc4cf 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs @@ -53,5 +53,20 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion { dest = Unsafe.As(ref this); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToVector4() + { + return new Vector4(this.r, this.g, this.b, this.a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyToVector4(ref Vector4 dest) + { + dest.X = this.r; + dest.Y = this.g; + dest.Z = this.b; + dest.W = this.a; + } } } \ No newline at end of file From 0f4f8227907fd142b092a112737b5ace6c50c21a Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 19 Oct 2018 13:14:33 +0200 Subject: [PATCH 172/381] cleanup --- .../SimdUtils.ExtendedIntrinsics.cs | 32 +++-- .../{Extensions => Helpers}/SimdUtils.cs | 18 +-- .../PixelFormats/PixelOperations{TPixel}.cs | 56 +++++---- .../PixelFormats/Rgba32.PixelOperations.cs | 69 ++++++++--- .../Color/Bulk/ToVector4.cs | 112 ++++++++++++++++-- .../PixelFormats/PixelOperationsTests.cs | 2 +- 6 files changed, 220 insertions(+), 69 deletions(-) rename src/ImageSharp/Common/{Extensions => Helpers}/SimdUtils.ExtendedIntrinsics.cs (81%) rename src/ImageSharp/Common/{Extensions => Helpers}/SimdUtils.cs (96%) diff --git a/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs similarity index 81% rename from src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs rename to src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index fba54b033a..6def8938a9 100644 --- a/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp { public static bool IsAvailable { get; } = #if NETCOREAPP2_1 -// TODO: Add a build target for .NET 4.7.2 +// TODO: Also available in .NET 4.7.2, we need to add a build target! true; #else false; @@ -31,14 +31,15 @@ namespace SixLabors.ImageSharp internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { Guard.IsTrue( - source.Length % Vector.Count == 0, + dest.Length % Vector.Count == 0, nameof(source), "dest.Length should be divisable by Vector.Count!"); - int n = source.Length / Vector.Count; + int n = dest.Length / Vector.Count; ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + ref Vector destBaseU = ref Unsafe.As, Vector>(ref destBase); const float Scale = 1f / 255f; @@ -50,16 +51,23 @@ namespace SixLabors.ImageSharp Vector.Widen(s0, out Vector w0, out Vector w1); Vector.Widen(s1, out Vector w2, out Vector w3); - Vector f0 = Vector.ConvertToSingle(w0) * Scale; - Vector f1 = Vector.ConvertToSingle(w1) * Scale; - Vector f2 = Vector.ConvertToSingle(w2) * Scale; - Vector f3 = Vector.ConvertToSingle(w3) * Scale; + ref Vector d = ref Unsafe.Add(ref destBaseU, i * 4); + d = w0; + Unsafe.Add(ref d, 1) = w1; + Unsafe.Add(ref d, 2) = w2; + Unsafe.Add(ref d, 3) = w3; + } + + n = dest.Length / Vector.Count; + + for (int i = 0; i < n; i++) + { + ref Vector df = ref Unsafe.Add(ref destBase, i); + ref Vector du = ref Unsafe.As, Vector>(ref df); - ref Vector d = ref Unsafe.Add(ref destBase, i * 4); - d = f0; - Unsafe.Add(ref d, 1) = f1; - Unsafe.Add(ref d, 2) = f2; - Unsafe.Add(ref d, 3) = f3; + Vector v = Vector.ConvertToSingle(du); + v *= Scale; + df = v; } } diff --git a/src/ImageSharp/Common/Extensions/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs similarity index 96% rename from src/ImageSharp/Common/Extensions/SimdUtils.cs rename to src/ImageSharp/Common/Helpers/SimdUtils.cs index 3630ede327..91aed8c79a 100644 --- a/src/ImageSharp/Common/Extensions/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -2,13 +2,10 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.PixelFormats; - namespace SixLabors.ImageSharp { /// @@ -131,23 +128,26 @@ namespace SixLabors.ImageSharp ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsWideOctet); int n = dest.Length / 8; - Octet.OfUInt32 temp = default; for (int i = 0; i < n; i++) { - Octet.OfByte sVal = Unsafe.Add(ref sourceBase, i); + ref Octet.OfByte s = ref Unsafe.Add(ref sourceBase, i); + ref Octet.OfUInt32 d = ref Unsafe.Add(ref destBaseAsWideOctet, i); + d.LoadFrom(ref s); + } - // This call is the bottleneck now: - temp.LoadFrom(ref sVal); + for (int i = 0; i < n; i++) + { + ref Vector df = ref Unsafe.Add(ref destBaseAsFloat, i); - Vector vi = Unsafe.As>(ref temp); + var vi = Vector.AsVectorUInt32(df); vi &= mask; vi |= magicInt; var vf = Vector.AsVectorSingle(vi); vf = (vf - magicFloat) * bVec; - Unsafe.Add(ref destBaseAsFloat, i) = vf; + df = vf; } } diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index b12a2bfa58..39c442fe02 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -29,17 +29,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void PackFromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) { - GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); - - ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); - ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); - - for (int i = 0; i < count; i++) - { - ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromVector4(sp); - } + PackFromVector4Common(sourceVectors, destinationColors, count); } /// @@ -50,17 +40,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) { - GuardSpans(sourceColors, nameof(sourceColors), destinationVectors, nameof(destinationVectors), count); - - ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); - ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); - - for (int i = 0; i < count; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); - ref Vector4 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToVector4(); - } + ToVector4Common(sourceColors, destinationVectors, count); } /// @@ -126,5 +106,37 @@ namespace SixLabors.ImageSharp.PixelFormats Guard.MustBeSizedAtLeast(source, minLength, sourceParamName); Guard.MustBeSizedAtLeast(destination, minLength, destinationParamName); } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void PackFromVector4Common(ReadOnlySpan sourceVectors, Span destinationColors, int count) + { + GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); + + ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); + ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); + + for (int i = 0; i < count; i++) + { + ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + dp.PackFromVector4(sp); + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void ToVector4Common(ReadOnlySpan sourceColors, Span destinationVectors, int count) + { + GuardSpans(sourceColors, nameof(sourceColors), destinationVectors, nameof(destinationVectors), count); + + ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); + ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); + + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref Vector4 dp = ref Unsafe.Add(ref destRef, i); + dp = sp.ToVector4(); + } + } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs index 6745079da5..0b96a599b6 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs @@ -27,28 +27,17 @@ namespace SixLabors.ImageSharp.PixelFormats if (count < 128 || !SimdUtils.IsAvx2CompatibleArchitecture) { // Doesn't worth to bother with SIMD: - base.ToVector4(sourceColors, destinationVectors, count); + ToVector4Common(sourceColors, destinationVectors, count); return; } - int remainder = count % 2; - int alignedCount = count - remainder; - - if (alignedCount > 0) + if (SimdUtils.ExtendedIntrinsics.IsAvailable) { - ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceColors); - Span rawDest = MemoryMarshal.Cast(destinationVectors.Slice(0, alignedCount)); - - SimdUtils.BulkConvertByteToNormalizedFloat( - rawSrc, - rawDest); + ConvertToVector4UsingExtendedIntrinsics(sourceColors, destinationVectors, count); } - - if (remainder > 0) + else { - // actually: remainder == 1 - int lastIdx = count - 1; - destinationVectors[lastIdx] = sourceColors[lastIdx].ToVector4(); + ConvertToVector4UsingStandardIntrinsics(sourceColors, destinationVectors, count); } } @@ -59,7 +48,7 @@ namespace SixLabors.ImageSharp.PixelFormats if (count < 128 || !SimdUtils.IsAvx2CompatibleArchitecture) { - base.PackFromVector4(sourceVectors, destinationColors, count); + PackFromVector4Common(sourceVectors, destinationColors, count); return; } @@ -109,6 +98,52 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(dest); } + + private static void ConvertToVector4UsingExtendedIntrinsics( + ReadOnlySpan sourceColors, + Span destinationVectors, + int count) + { + int remainder = count % 8; + int alignedCount = count - remainder; + + if (alignedCount > 0) + { + ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceColors); + Span rawDest = MemoryMarshal.Cast(destinationVectors.Slice(0, alignedCount)); + + SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(rawSrc, rawDest); + } + + if (remainder > 0) + { + ToVector4Common(sourceColors.Slice(alignedCount), destinationVectors.Slice(alignedCount), remainder); + } + } + + private static void ConvertToVector4UsingStandardIntrinsics( + ReadOnlySpan sourceColors, + Span destinationVectors, + int count) + { + int remainder = count % 2; + int alignedCount = count - remainder; + + if (alignedCount > 0) + { + ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceColors); + Span rawDest = MemoryMarshal.Cast(destinationVectors.Slice(0, alignedCount)); + + SimdUtils.BulkConvertByteToNormalizedFloat(rawSrc, rawDest); + } + + if (remainder > 0) + { + // actually: remainder == 1 + int lastIdx = count - 1; + destinationVectors[lastIdx] = sourceColors[lastIdx].ToVector4(); + } + } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 39c1fbd474..6afd3cf6b1 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -6,6 +6,7 @@ using System.Buffers; using System; using System.Numerics; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; @@ -28,7 +29,9 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Params( //64, - 2048)] + //512 + 256 + )] public int Count { get; set; } [GlobalSetup] @@ -45,7 +48,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.destination.Dispose(); } - [Benchmark] + //[Benchmark] public void PerElement() { Span s = this.source.GetSpan(); @@ -53,32 +56,48 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk for (int i = 0; i < this.Count; i++) { - TPixel c = s[i]; - d[i] = c.ToVector4(); + d[i] = s[i].ToVector4(); } } - [Benchmark(Baseline = true)] + //[Benchmark] public void CommonBulk() { new PixelOperations().ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } - [Benchmark] + //[Benchmark] public void OptimizedBulk() { PixelOperations.Instance.ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } } - [CoreJob] - [ClrJob] + [RyuJitX64Job] + [DisassemblyDiagnoser(printAsm: true, printSource: true)] public class ToVector4_Rgba32 : ToVector4 { class Config : ManualConfig { } + [Benchmark(Baseline = true)] + public void FastScalarBulk() + { + ref Rgba32 sBase = ref this.source.GetSpan()[0]; + ref Vector4 dBase = ref this.destination.GetSpan()[0]; + + for (int i = 0; i < this.Count; i++) + { + ref Rgba32 s = ref Unsafe.Add(ref sBase, i); + ref Vector4 d = ref Unsafe.Add(ref dBase, i); + d.X = s.R; + d.Y = s.G; + d.Z = s.B; + d.W = s.A; + } + } + [Benchmark] public void BulkConvertByteToNormalizedFloat() { @@ -97,5 +116,82 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats); } + //[Benchmark] + public void Original() + { + ToVector4SimdAligned(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void ToVector4SimdAligned(ReadOnlySpan sourceColors, Span destVectors, int count) + { + if (!Vector.IsHardwareAccelerated) + { + throw new InvalidOperationException( + "Rgba32.PixelOperations.ToVector4SimdAligned() should not be called when Vector.IsHardwareAccelerated == false!"); + } + + DebugGuard.IsTrue( + count % Vector.Count == 0, + nameof(count), + "Argument 'count' should divisible by Vector.Count!"); + + var bVec = new Vector(256.0f / 255.0f); + var magicFloat = new Vector(32768.0f); + var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f + var mask = new Vector(255); + + int unpackedRawCount = count * 4; + + ref uint sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference(sourceColors)); + ref UnpackedRGBA destBaseAsUnpacked = ref Unsafe.As(ref MemoryMarshal.GetReference(destVectors)); + ref Vector destBaseAsUInt = ref Unsafe.As>(ref destBaseAsUnpacked); + ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsUnpacked); + + for (int i = 0; i < count; i++) + { + uint sVal = Unsafe.Add(ref sourceBase, i); + ref UnpackedRGBA dst = ref Unsafe.Add(ref destBaseAsUnpacked, i); + + // This call is the bottleneck now: + dst.Load(sVal); + } + + int numOfVectors = unpackedRawCount / Vector.Count; + + for (int i = 0; i < numOfVectors; i++) + { + Vector vi = Unsafe.Add(ref destBaseAsUInt, i); + + vi &= mask; + vi |= magicInt; + + var vf = Vector.AsVectorSingle(vi); + vf = (vf - magicFloat) * bVec; + + Unsafe.Add(ref destBaseAsFloat, i) = vf; + } + } + + [StructLayout(LayoutKind.Sequential)] + private struct UnpackedRGBA + { + private uint r; + + private uint g; + + private uint b; + + private uint a; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Load(uint p) + { + this.r = p; + this.g = p >> 8; + this.b = p >> 16; + this.a = p >> 24; + } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 535952e051..abf764881b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { } - public static TheoryData ArraySizesData => new TheoryData { 0, 1, 2, 7, 16, 1111 }; + public static TheoryData ArraySizesData => new TheoryData { 0, 1, 2, 7, 16, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 1111 }; private static PixelOperations Operations => PixelOperations.Instance; From 0e06eb635557d3e021d7afee3ee41c1f28a5575d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 19 Oct 2018 13:38:03 +0200 Subject: [PATCH 173/381] benchmark conversion steps separately --- .../General/Vectorization/UInt32ToSingle.cs | 66 +++++++++++++++++++ .../Vectorization/WidenBytesToUInt32.cs | 61 +++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs create mode 100644 tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs new file mode 100644 index 0000000000..4a4b939b65 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs @@ -0,0 +1,66 @@ +using System.Numerics; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization +{ + public class UInt32ToSingle + { + private float[] data; + + private const int Count = 64; + + [GlobalSetup] + public void Setup() + { + this.data = new float[Count]; + } + + [Benchmark(Baseline = true)] + public void MagicMethod() + { + ref Vector b = ref Unsafe.As>(ref this.data[0]); + + int n = Count / Vector.Count; + + Vector magick = new Vector(32768.0f); + Vector scale = new Vector(255f) / new Vector(256f); + + for (int i = 0; i < n; i++) + { + // union { float f; uint32_t i; } u; + // u.f = 32768.0f + x * (255.0f / 256.0f); + // return (uint8_t)u.i; + + ref Vector d = ref Unsafe.Add(ref b, i); + Vector x = d; + //x = Vector.Max(x, Vector.Zero); + //x = Vector.Min(x, Vector.One); + + x = (x * scale) + magick; + d = x; + } + } + + [Benchmark] + public void StandardSimd() + { + int n = Count / Vector.Count; + + ref Vector b = ref Unsafe.As>(ref this.data[0]); + + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + ref Vector df = ref Unsafe.Add(ref b, i); + Vector du = Unsafe.As, Vector>(ref df); + + Vector v = Vector.ConvertToSingle(du); + v *= scale; + df = v; + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs new file mode 100644 index 0000000000..f71f6ec1bf --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs @@ -0,0 +1,61 @@ +using System.Numerics; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization +{ + public class WidenBytesToUInt32 + { + private byte[] source; + + private uint[] dest; + + private const int Count = 64; + + [GlobalSetup] + public void Setup() + { + this.source = new byte[Count]; + this.dest = new uint[Count]; + } + + [Benchmark(Baseline = true)] + public void Standard() + { + const int N = Count / 8; + + ref SimdUtils.Octet.OfByte sBase = ref Unsafe.As(ref this.source[0]); + ref SimdUtils.Octet.OfUInt32 dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < N; i++) + { + Unsafe.Add(ref dBase, i).LoadFrom(ref Unsafe.Add(ref sBase, i)); + } + } + + [Benchmark] + public void Simd() + { + int n = Count / Vector.Count; + + ref Vector sBase = ref Unsafe.As>(ref this.source[0]); + ref Vector dBase = ref Unsafe.As>(ref this.dest[0]); + + for (int i = 0; i < n; i++) + { + Vector b = Unsafe.Add(ref sBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + ref Vector d = ref Unsafe.Add(ref dBase, i * 4); + d = w0; + Unsafe.Add(ref d, 1) = w1; + Unsafe.Add(ref d, 2) = w2; + Unsafe.Add(ref d, 3) = w3; + } + } + } +} \ No newline at end of file From 9370a6e5354f25687a6da4da83e29ddf835e7b85 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 19 Oct 2018 21:56:27 +0100 Subject: [PATCH 174/381] Add generic palette quantizer, refactor + werner palette --- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 5 +- src/ImageSharp/PixelFormats/ColorConstants.cs | 409 +++++++++++------- .../PixelFormats/NamedColors{TPixel}.cs | 26 +- src/ImageSharp/Processing/KnownQuantizers.cs | 13 +- .../Quantization/OctreeQuantizer.cs | 13 +- .../PaletteFrameQuantizer{TPixel}.cs | 5 +- .../Quantization/PaletteQuantizer.cs | 50 +-- .../Quantization/PaletteQuantizer{TPixel}.cs | 92 ++++ .../Quantization/QuantizerConstants.cs | 21 + .../Quantization/WebSafePaletteQuantizer.cs | 47 ++ .../Quantization/WernerPaletteQuantizer.cs | 48 ++ .../Processors/Quantization/WuQuantizer.cs | 13 +- .../ImageSharp.Benchmarks/Codecs/EncodeGif.cs | 2 +- .../Codecs/EncodeGifMultiple.cs | 2 +- .../Codecs/EncodeIndexedPng.cs | 4 +- .../Formats/GeneralFormatTests.cs | 3 +- .../Formats/Gif/GifEncoderTests.cs | 2 +- .../Quantization/QuantizedImageTests.cs | 11 +- 18 files changed, 545 insertions(+), 221 deletions(-) create mode 100644 src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs create mode 100644 src/ImageSharp/Processing/Processors/Quantization/QuantizerConstants.cs create mode 100644 src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs create mode 100644 src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index ae0366e6e6..a8cd169e5d 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -133,7 +133,7 @@ namespace SixLabors.ImageSharp.Formats.Gif private void EncodeGlobal(Image image, QuantizedFrame quantized, int transparencyIndex, Stream stream) where TPixel : struct, IPixel { - var palleteQuantizer = new PaletteQuantizer(this.quantizer.Diffuser); + var palleteQuantizer = new PaletteQuantizer(quantized.Palette, this.quantizer.Diffuser); for (int i = 0; i < image.Frames.Count; i++) { @@ -149,8 +149,7 @@ namespace SixLabors.ImageSharp.Formats.Gif } else { - using (QuantizedFrame paletteQuantized - = palleteQuantizer.CreateFrameQuantizer(() => quantized.Palette).QuantizeFrame(frame)) + using (QuantizedFrame paletteQuantized = palleteQuantizer.CreateFrameQuantizer().QuantizeFrame(frame)) { this.WriteImageData(paletteQuantized, stream); } diff --git a/src/ImageSharp/PixelFormats/ColorConstants.cs b/src/ImageSharp/PixelFormats/ColorConstants.cs index bac05c53d2..14df385697 100644 --- a/src/ImageSharp/PixelFormats/ColorConstants.cs +++ b/src/ImageSharp/PixelFormats/ColorConstants.cs @@ -11,157 +11,268 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Gets a collection of named, web safe, colors as defined in the CSS Color Module Level 4. /// - public static readonly Rgba32[] WebSafeColors = GetWebSafeColors(); + public static readonly Rgba32[] WebSafeColors = + { + Rgba32.AliceBlue, + Rgba32.AntiqueWhite, + Rgba32.Aqua, + Rgba32.Aquamarine, + Rgba32.Azure, + Rgba32.Beige, + Rgba32.Bisque, + Rgba32.Black, + Rgba32.BlanchedAlmond, + Rgba32.Blue, + Rgba32.BlueViolet, + Rgba32.Brown, + Rgba32.BurlyWood, + Rgba32.CadetBlue, + Rgba32.Chartreuse, + Rgba32.Chocolate, + Rgba32.Coral, + Rgba32.CornflowerBlue, + Rgba32.Cornsilk, + Rgba32.Crimson, + Rgba32.Cyan, + Rgba32.DarkBlue, + Rgba32.DarkCyan, + Rgba32.DarkGoldenrod, + Rgba32.DarkGray, + Rgba32.DarkGreen, + Rgba32.DarkKhaki, + Rgba32.DarkMagenta, + Rgba32.DarkOliveGreen, + Rgba32.DarkOrange, + Rgba32.DarkOrchid, + Rgba32.DarkRed, + Rgba32.DarkSalmon, + Rgba32.DarkSeaGreen, + Rgba32.DarkSlateBlue, + Rgba32.DarkSlateGray, + Rgba32.DarkTurquoise, + Rgba32.DarkViolet, + Rgba32.DeepPink, + Rgba32.DeepSkyBlue, + Rgba32.DimGray, + Rgba32.DodgerBlue, + Rgba32.Firebrick, + Rgba32.FloralWhite, + Rgba32.ForestGreen, + Rgba32.Fuchsia, + Rgba32.Gainsboro, + Rgba32.GhostWhite, + Rgba32.Gold, + Rgba32.Goldenrod, + Rgba32.Gray, + Rgba32.Green, + Rgba32.GreenYellow, + Rgba32.Honeydew, + Rgba32.HotPink, + Rgba32.IndianRed, + Rgba32.Indigo, + Rgba32.Ivory, + Rgba32.Khaki, + Rgba32.Lavender, + Rgba32.LavenderBlush, + Rgba32.LawnGreen, + Rgba32.LemonChiffon, + Rgba32.LightBlue, + Rgba32.LightCoral, + Rgba32.LightCyan, + Rgba32.LightGoldenrodYellow, + Rgba32.LightGray, + Rgba32.LightGreen, + Rgba32.LightPink, + Rgba32.LightSalmon, + Rgba32.LightSeaGreen, + Rgba32.LightSkyBlue, + Rgba32.LightSlateGray, + Rgba32.LightSteelBlue, + Rgba32.LightYellow, + Rgba32.Lime, + Rgba32.LimeGreen, + Rgba32.Linen, + Rgba32.Magenta, + Rgba32.Maroon, + Rgba32.MediumAquamarine, + Rgba32.MediumBlue, + Rgba32.MediumOrchid, + Rgba32.MediumPurple, + Rgba32.MediumSeaGreen, + Rgba32.MediumSlateBlue, + Rgba32.MediumSpringGreen, + Rgba32.MediumTurquoise, + Rgba32.MediumVioletRed, + Rgba32.MidnightBlue, + Rgba32.MintCream, + Rgba32.MistyRose, + Rgba32.Moccasin, + Rgba32.NavajoWhite, + Rgba32.Navy, + Rgba32.OldLace, + Rgba32.Olive, + Rgba32.OliveDrab, + Rgba32.Orange, + Rgba32.OrangeRed, + Rgba32.Orchid, + Rgba32.PaleGoldenrod, + Rgba32.PaleGreen, + Rgba32.PaleTurquoise, + Rgba32.PaleVioletRed, + Rgba32.PapayaWhip, + Rgba32.PeachPuff, + Rgba32.Peru, + Rgba32.Pink, + Rgba32.Plum, + Rgba32.PowderBlue, + Rgba32.Purple, + Rgba32.RebeccaPurple, + Rgba32.Red, + Rgba32.RosyBrown, + Rgba32.RoyalBlue, + Rgba32.SaddleBrown, + Rgba32.Salmon, + Rgba32.SandyBrown, + Rgba32.SeaGreen, + Rgba32.SeaShell, + Rgba32.Sienna, + Rgba32.Silver, + Rgba32.SkyBlue, + Rgba32.SlateBlue, + Rgba32.SlateGray, + Rgba32.Snow, + Rgba32.SpringGreen, + Rgba32.SteelBlue, + Rgba32.Tan, + Rgba32.Teal, + Rgba32.Thistle, + Rgba32.Tomato, + Rgba32.Transparent, + Rgba32.Turquoise, + Rgba32.Violet, + Rgba32.Wheat, + Rgba32.White, + Rgba32.WhiteSmoke, + Rgba32.Yellow, + Rgba32.YellowGreen + }; /// - /// Returns an array of web safe colors. + /// Gets a collection of colors as defined in the original second edition of Werner’s Nomenclature of Colours 1821. + /// The hex codes were collected and defined by Nicholas Rougeux /// - /// The - private static Rgba32[] GetWebSafeColors() - => new Rgba32[] - { - Rgba32.AliceBlue, - Rgba32.AntiqueWhite, - Rgba32.Aqua, - Rgba32.Aquamarine, - Rgba32.Azure, - Rgba32.Beige, - Rgba32.Bisque, - Rgba32.Black, - Rgba32.BlanchedAlmond, - Rgba32.Blue, - Rgba32.BlueViolet, - Rgba32.Brown, - Rgba32.BurlyWood, - Rgba32.CadetBlue, - Rgba32.Chartreuse, - Rgba32.Chocolate, - Rgba32.Coral, - Rgba32.CornflowerBlue, - Rgba32.Cornsilk, - Rgba32.Crimson, - Rgba32.Cyan, - Rgba32.DarkBlue, - Rgba32.DarkCyan, - Rgba32.DarkGoldenrod, - Rgba32.DarkGray, - Rgba32.DarkGreen, - Rgba32.DarkKhaki, - Rgba32.DarkMagenta, - Rgba32.DarkOliveGreen, - Rgba32.DarkOrange, - Rgba32.DarkOrchid, - Rgba32.DarkRed, - Rgba32.DarkSalmon, - Rgba32.DarkSeaGreen, - Rgba32.DarkSlateBlue, - Rgba32.DarkSlateGray, - Rgba32.DarkTurquoise, - Rgba32.DarkViolet, - Rgba32.DeepPink, - Rgba32.DeepSkyBlue, - Rgba32.DimGray, - Rgba32.DodgerBlue, - Rgba32.Firebrick, - Rgba32.FloralWhite, - Rgba32.ForestGreen, - Rgba32.Fuchsia, - Rgba32.Gainsboro, - Rgba32.GhostWhite, - Rgba32.Gold, - Rgba32.Goldenrod, - Rgba32.Gray, - Rgba32.Green, - Rgba32.GreenYellow, - Rgba32.Honeydew, - Rgba32.HotPink, - Rgba32.IndianRed, - Rgba32.Indigo, - Rgba32.Ivory, - Rgba32.Khaki, - Rgba32.Lavender, - Rgba32.LavenderBlush, - Rgba32.LawnGreen, - Rgba32.LemonChiffon, - Rgba32.LightBlue, - Rgba32.LightCoral, - Rgba32.LightCyan, - Rgba32.LightGoldenrodYellow, - Rgba32.LightGray, - Rgba32.LightGreen, - Rgba32.LightPink, - Rgba32.LightSalmon, - Rgba32.LightSeaGreen, - Rgba32.LightSkyBlue, - Rgba32.LightSlateGray, - Rgba32.LightSteelBlue, - Rgba32.LightYellow, - Rgba32.Lime, - Rgba32.LimeGreen, - Rgba32.Linen, - Rgba32.Magenta, - Rgba32.Maroon, - Rgba32.MediumAquamarine, - Rgba32.MediumBlue, - Rgba32.MediumOrchid, - Rgba32.MediumPurple, - Rgba32.MediumSeaGreen, - Rgba32.MediumSlateBlue, - Rgba32.MediumSpringGreen, - Rgba32.MediumTurquoise, - Rgba32.MediumVioletRed, - Rgba32.MidnightBlue, - Rgba32.MintCream, - Rgba32.MistyRose, - Rgba32.Moccasin, - Rgba32.NavajoWhite, - Rgba32.Navy, - Rgba32.OldLace, - Rgba32.Olive, - Rgba32.OliveDrab, - Rgba32.Orange, - Rgba32.OrangeRed, - Rgba32.Orchid, - Rgba32.PaleGoldenrod, - Rgba32.PaleGreen, - Rgba32.PaleTurquoise, - Rgba32.PaleVioletRed, - Rgba32.PapayaWhip, - Rgba32.PeachPuff, - Rgba32.Peru, - Rgba32.Pink, - Rgba32.Plum, - Rgba32.PowderBlue, - Rgba32.Purple, - Rgba32.RebeccaPurple, - Rgba32.Red, - Rgba32.RosyBrown, - Rgba32.RoyalBlue, - Rgba32.SaddleBrown, - Rgba32.Salmon, - Rgba32.SandyBrown, - Rgba32.SeaGreen, - Rgba32.SeaShell, - Rgba32.Sienna, - Rgba32.Silver, - Rgba32.SkyBlue, - Rgba32.SlateBlue, - Rgba32.SlateGray, - Rgba32.Snow, - Rgba32.SpringGreen, - Rgba32.SteelBlue, - Rgba32.Tan, - Rgba32.Teal, - Rgba32.Thistle, - Rgba32.Tomato, - Rgba32.Transparent, - Rgba32.Turquoise, - Rgba32.Violet, - Rgba32.Wheat, - Rgba32.White, - Rgba32.WhiteSmoke, - Rgba32.Yellow, - Rgba32.YellowGreen - }; + public static readonly Rgba32[] WernerColors = + { + Rgba32.FromHex("#f1e9cd"), + Rgba32.FromHex("#f2e7cf"), + Rgba32.FromHex("#ece6d0"), + Rgba32.FromHex("#f2eacc"), + Rgba32.FromHex("#f3e9ca"), + Rgba32.FromHex("#f2ebcd"), + Rgba32.FromHex("#e6e1c9"), + Rgba32.FromHex("#e2ddc6"), + Rgba32.FromHex("#cbc8b7"), + Rgba32.FromHex("#bfbbb0"), + Rgba32.FromHex("#bebeb3"), + Rgba32.FromHex("#b7b5ac"), + Rgba32.FromHex("#bab191"), + Rgba32.FromHex("#9c9d9a"), + Rgba32.FromHex("#8a8d84"), + Rgba32.FromHex("#5b5c61"), + Rgba32.FromHex("#555152"), + Rgba32.FromHex("#413f44"), + Rgba32.FromHex("#454445"), + Rgba32.FromHex("#423937"), + Rgba32.FromHex("#433635"), + Rgba32.FromHex("#252024"), + Rgba32.FromHex("#241f20"), + Rgba32.FromHex("#281f3f"), + Rgba32.FromHex("#1c1949"), + Rgba32.FromHex("#4f638d"), + Rgba32.FromHex("#383867"), + Rgba32.FromHex("#5c6b8f"), + Rgba32.FromHex("#657abb"), + Rgba32.FromHex("#6f88af"), + Rgba32.FromHex("#7994b5"), + Rgba32.FromHex("#6fb5a8"), + Rgba32.FromHex("#719ba2"), + Rgba32.FromHex("#8aa1a6"), + Rgba32.FromHex("#d0d5d3"), + Rgba32.FromHex("#8590ae"), + Rgba32.FromHex("#3a2f52"), + Rgba32.FromHex("#39334a"), + Rgba32.FromHex("#6c6d94"), + Rgba32.FromHex("#584c77"), + Rgba32.FromHex("#533552"), + Rgba32.FromHex("#463759"), + Rgba32.FromHex("#bfbac0"), + Rgba32.FromHex("#77747f"), + Rgba32.FromHex("#4a475c"), + Rgba32.FromHex("#b8bfaf"), + Rgba32.FromHex("#b2b599"), + Rgba32.FromHex("#979c84"), + Rgba32.FromHex("#5d6161"), + Rgba32.FromHex("#61ac86"), + Rgba32.FromHex("#a4b6a7"), + Rgba32.FromHex("#adba98"), + Rgba32.FromHex("#93b778"), + Rgba32.FromHex("#7d8c55"), + Rgba32.FromHex("#33431e"), + Rgba32.FromHex("#7c8635"), + Rgba32.FromHex("#8e9849"), + Rgba32.FromHex("#c2c190"), + Rgba32.FromHex("#67765b"), + Rgba32.FromHex("#ab924b"), + Rgba32.FromHex("#c8c76f"), + Rgba32.FromHex("#ccc050"), + Rgba32.FromHex("#ebdd99"), + Rgba32.FromHex("#ab9649"), + Rgba32.FromHex("#dbc364"), + Rgba32.FromHex("#e6d058"), + Rgba32.FromHex("#ead665"), + Rgba32.FromHex("#d09b2c"), + Rgba32.FromHex("#a36629"), + Rgba32.FromHex("#a77d35"), + Rgba32.FromHex("#f0d696"), + Rgba32.FromHex("#d7c485"), + Rgba32.FromHex("#f1d28c"), + Rgba32.FromHex("#efcc83"), + Rgba32.FromHex("#f3daa7"), + Rgba32.FromHex("#dfa837"), + Rgba32.FromHex("#ebbc71"), + Rgba32.FromHex("#d17c3f"), + Rgba32.FromHex("#92462f"), + Rgba32.FromHex("#be7249"), + Rgba32.FromHex("#bb603c"), + Rgba32.FromHex("#c76b4a"), + Rgba32.FromHex("#a75536"), + Rgba32.FromHex("#b63e36"), + Rgba32.FromHex("#b5493a"), + Rgba32.FromHex("#cd6d57"), + Rgba32.FromHex("#711518"), + Rgba32.FromHex("#e9c49d"), + Rgba32.FromHex("#eedac3"), + Rgba32.FromHex("#eecfbf"), + Rgba32.FromHex("#ce536b"), + Rgba32.FromHex("#b74a70"), + Rgba32.FromHex("#b7757c"), + Rgba32.FromHex("#612741"), + Rgba32.FromHex("#7a4848"), + Rgba32.FromHex("#3f3033"), + Rgba32.FromHex("#8d746f"), + Rgba32.FromHex("#4d3635"), + Rgba32.FromHex("#6e3b31"), + Rgba32.FromHex("#864735"), + Rgba32.FromHex("#553d3a"), + Rgba32.FromHex("#613936"), + Rgba32.FromHex("#7a4b3a"), + Rgba32.FromHex("#946943"), + Rgba32.FromHex("#c39e6d"), + Rgba32.FromHex("#513e32"), + Rgba32.FromHex("#8b7859"), + Rgba32.FromHex("#9b856b"), + Rgba32.FromHex("#766051"), + Rgba32.FromHex("#453b32") + }; } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs index 0f42e182c5..a0916b1636 100644 --- a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs @@ -14,9 +14,10 @@ namespace SixLabors.ImageSharp.PixelFormats where TPixel : struct, IPixel { /// - /// Thread-safe backing field for . + /// Thread-safe backing field for the constant palettes. /// private static readonly Lazy WebSafePaletteLazy = new Lazy(GetWebSafePalette, true); + private static readonly Lazy WernerPaletteLazy = new Lazy(GetWernerPalette, true); /// /// Represents a matching the W3C definition that has an hex value of #F0F8FF. @@ -729,18 +730,27 @@ namespace SixLabors.ImageSharp.PixelFormats public static readonly TPixel YellowGreen = ColorBuilder.FromRGBA(154, 205, 50, 255); /// - /// Gets a matching the W3C definition of web safe colors. + /// Gets a collection of web safe, colors as defined in the CSS Color Module Level 4. /// public static TPixel[] WebSafePalette => WebSafePaletteLazy.Value; - private static TPixel[] GetWebSafePalette() + /// + /// Gets a collection of colors as defined in the original second edition of Werner’s Nomenclature of Colours 1821. + /// The hex codes were collected and defined by Nicholas Rougeux + /// + public static TPixel[] WernerPalette => WernerPaletteLazy.Value; + + private static TPixel[] GetWebSafePalette() => GetPalette(ColorConstants.WebSafeColors); + + private static TPixel[] GetWernerPalette() => GetPalette(ColorConstants.WernerColors); + + private static TPixel[] GetPalette(Rgba32[] palette) { - Rgba32[] constants = ColorConstants.WebSafeColors; - var safe = new TPixel[constants.Length + 1]; + var converted = new TPixel[palette.Length + 1]; - Span constantsBytes = MemoryMarshal.Cast(constants.AsSpan()); - PixelOperations.Instance.PackFromRgba32Bytes(constantsBytes, safe, constants.Length); - return safe; + Span constantsBytes = MemoryMarshal.Cast(palette.AsSpan()); + PixelOperations.Instance.PackFromRgba32Bytes(constantsBytes, converted, palette.Length); + return converted; } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/KnownQuantizers.cs b/src/ImageSharp/Processing/KnownQuantizers.cs index fe98063104..e93a9921a9 100644 --- a/src/ImageSharp/Processing/KnownQuantizers.cs +++ b/src/ImageSharp/Processing/KnownQuantizers.cs @@ -23,9 +23,16 @@ namespace SixLabors.ImageSharp.Processing public static IQuantizer Wu { get; } = new WuQuantizer(); /// - /// Gets the palette based, Using the collection of web-safe colors. - /// The quantizer supports multiple alpha values. + /// Gets the palette based quantizer consisting of web safe colors as defined in the CSS Color Module Level 4. + /// The quantizer supports a single alpha value. + /// + public static IQuantizer WebSafe { get; } = new WebSafePaletteQuantizer(); + + /// + /// Gets the palette based quantizer consisting of colors as defined in the original second edition of Werner’s Nomenclature of Colours 1821. + /// The hex codes were collected and defined by Nicholas Rougeux + /// The quantizer supports a single alpha value. /// - public static IQuantizer Palette { get; } = new PaletteQuantizer(); + public static IQuantizer Werner { get; } = new WernerPaletteQuantizer(); } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs index 22bb5223f0..d0dd18393e 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs @@ -15,11 +15,6 @@ 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. /// @@ -42,7 +37,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Whether to apply dithering to the output image public OctreeQuantizer(bool dither) - : this(GetDiffuser(dither), DefaultMaxColors) + : this(GetDiffuser(dither), QuantizerConstants.MaxColors) { } @@ -51,7 +46,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, DefaultMaxColors) + : this(diffuser, QuantizerConstants.MaxColors) { } @@ -63,7 +58,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public OctreeQuantizer(IErrorDiffuser diffuser, int maxColors) { this.Diffuser = diffuser; - this.MaxColors = maxColors.Clamp(1, DefaultMaxColors); + this.MaxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); } /// @@ -83,7 +78,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public IFrameQuantizer CreateFrameQuantizer(int maxColors) where TPixel : struct, IPixel { - maxColors = maxColors.Clamp(1, DefaultMaxColors); + maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); return new OctreeFrameQuantizer(this, maxColors); } diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs index cdf3514e2d..10f46e68ac 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs @@ -33,12 +33,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The palette quantizer. /// An array of all colors in the palette. - public PaletteFrameQuantizer(PaletteQuantizer quantizer, TPixel[] colors) + public PaletteFrameQuantizer(IQuantizer 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]; PixelOperations.Instance.ToScaledVector4(this.palette, this.paletteVector, this.palette.Length); diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs index 27ef05dfe9..5dace6b179 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs @@ -8,18 +8,18 @@ using SixLabors.ImageSharp.Processing.Processors.Dithering; namespace SixLabors.ImageSharp.Processing.Processors.Quantization { /// - /// Allows the quantization of images pixels using web safe colors defined in the CSS Color Module Level 4. - /// Override this class to provide your own palette. + /// Allows the quantization of images pixels using color palettes. + /// Override this class to provide your own palette. /// - /// By default the quantizer uses dithering and the + /// By default the quantizer uses dithering. /// /// - public class PaletteQuantizer : IQuantizer + public abstract class PaletteQuantizer : IQuantizer { /// /// Initializes a new instance of the class. /// - public PaletteQuantizer() + protected PaletteQuantizer() : this(true) { } @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Initializes a new instance of the class. /// /// Whether to apply dithering to the output image - public PaletteQuantizer(bool dither) + protected PaletteQuantizer(bool dither) : this(GetDiffuser(dither)) { } @@ -37,41 +37,39 @@ 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; + protected PaletteQuantizer(IErrorDiffuser diffuser) => this.Diffuser = diffuser; /// public IErrorDiffuser Diffuser { get; } /// - public virtual IFrameQuantizer CreateFrameQuantizer() - where TPixel : struct, IPixel - => this.CreateFrameQuantizer(() => NamedColors.WebSafePalette); + public abstract IFrameQuantizer CreateFrameQuantizer() + where TPixel : struct, IPixel; /// - public IFrameQuantizer CreateFrameQuantizer(int maxColors) + public abstract IFrameQuantizer CreateFrameQuantizer(int maxColors) + where TPixel : struct, IPixel; + + /// + /// Creates the generic frame quantizer. + /// + /// The pixel format. + /// The color palette. + /// The maximum number of colors to hold in the color palette. + /// The + protected IFrameQuantizer CreateFrameQuantizer(TPixel[] palette, int maxColors) where TPixel : struct, IPixel { - TPixel[] websafe = NamedColors.WebSafePalette; - int max = Math.Min(maxColors, websafe.Length); + int max = Math.Min(QuantizerConstants.MaxColors, Math.Min(maxColors, palette.Length)); - if (max != websafe.Length) + if (max != palette.Length) { - return this.CreateFrameQuantizer(() => NamedColors.WebSafePalette.AsSpan(0, max).ToArray()); + return new PaletteFrameQuantizer(this, palette.AsSpan(0, max).ToArray()); } - return this.CreateFrameQuantizer(() => websafe); + return new PaletteFrameQuantizer(this, palette); } - /// - /// Gets the palette to use to quantize the image. - /// - /// The pixel format. - /// The method to return the palette. - /// The - public IFrameQuantizer CreateFrameQuantizer(Func paletteFunction) - where TPixel : struct, IPixel - => new PaletteFrameQuantizer(this, paletteFunction.Invoke()); - private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null; } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs new file mode 100644 index 0000000000..02ffc76ef0 --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs @@ -0,0 +1,92 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Dithering; + +namespace SixLabors.ImageSharp.Processing.Processors.Quantization +{ + /// + /// A generic palette quantizer. + /// + /// The pixel format. + public class PaletteQuantizer : IQuantizer + where TPixel : struct, IPixel + { + private readonly TPixel[] palette; + + /// + /// Initializes a new instance of the class. + /// + /// The color palette to use. + public PaletteQuantizer(TPixel[] palette) + : this(palette, true) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The color palette to use. + /// Whether to apply dithering to the output image + public PaletteQuantizer(TPixel[] palette, bool dither) + : this(palette, GetDiffuser(dither)) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The color palette to use. + /// The error diffusion algorithm, if any, to apply to the output image + public PaletteQuantizer(TPixel[] palette, IErrorDiffuser diffuser) + { + Guard.MustBeBetweenOrEqualTo(palette.Length, QuantizerConstants.MinColors, QuantizerConstants.MaxColors, nameof(palette)); + this.palette = palette; + this.Diffuser = diffuser; + } + + /// + public IErrorDiffuser Diffuser { get; } + + /// + public IFrameQuantizer CreateFrameQuantizer() + where TPixel1 : struct, IPixel + { + if (!typeof(TPixel).Equals(typeof(TPixel1))) + { + throw new InvalidOperationException("Generic method type must be the same as class type."); + } + + TPixel[] paletteRef = this.palette; + return new PaletteFrameQuantizer(this, Unsafe.As(ref paletteRef)); + } + + /// + public IFrameQuantizer CreateFrameQuantizer(int maxColors) + where TPixel1 : struct, IPixel + { + if (!typeof(TPixel).Equals(typeof(TPixel1))) + { + throw new InvalidOperationException("Generic method type must be the same as class type."); + } + + TPixel[] paletteRef = this.palette; + TPixel1[] castPalette = Unsafe.As(ref paletteRef); + + maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); + int max = Math.Min(maxColors, castPalette.Length); + + if (max != castPalette.Length) + { + return new PaletteFrameQuantizer(this, castPalette.AsSpan(0, max).ToArray()); + } + + return new PaletteFrameQuantizer(this, castPalette); + } + + private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null; + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizerConstants.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizerConstants.cs new file mode 100644 index 0000000000..d79a91c301 --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizerConstants.cs @@ -0,0 +1,21 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Processing.Processors.Quantization +{ + /// + /// Contains color quantization specific constants. + /// + internal static class QuantizerConstants + { + /// + /// The minimum number of colors to use when quantizing an image. + /// + public const int MinColors = 1; + + /// + /// The maximum number of colors to use when quantizing an image. + /// + public const int MaxColors = 256; + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs new file mode 100644 index 0000000000..bfa368a2e5 --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs @@ -0,0 +1,47 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Dithering; + +namespace SixLabors.ImageSharp.Processing.Processors.Quantization +{ + /// + /// A palette quantizer consisting of web safe colors as defined in the CSS Color Module Level 4. + /// + public class WebSafePaletteQuantizer : PaletteQuantizer + { + /// + /// Initializes a new instance of the class. + /// + public WebSafePaletteQuantizer() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Whether to apply dithering to the output image + public WebSafePaletteQuantizer(bool dither) + : base(dither) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The error diffusion algorithm, if any, to apply to the output image + public WebSafePaletteQuantizer(IErrorDiffuser diffuser) + : base(diffuser) + { + } + + /// + public override IFrameQuantizer CreateFrameQuantizer() + => this.CreateFrameQuantizer(NamedColors.WebSafePalette.Length); + + /// + public override IFrameQuantizer CreateFrameQuantizer(int maxColors) + => this.CreateFrameQuantizer(NamedColors.WebSafePalette, maxColors); + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs new file mode 100644 index 0000000000..9a91a63d3d --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs @@ -0,0 +1,48 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Dithering; + +namespace SixLabors.ImageSharp.Processing.Processors.Quantization +{ + /// + /// A palette quantizer consisting of colors as defined in the original second edition of Werner’s Nomenclature of Colours 1821. + /// The hex codes were collected and defined by Nicholas Rougeux + /// + public class WernerPaletteQuantizer : PaletteQuantizer + { + /// + /// Initializes a new instance of the class. + /// + public WernerPaletteQuantizer() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Whether to apply dithering to the output image + public WernerPaletteQuantizer(bool dither) + : base(dither) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The error diffusion algorithm, if any, to apply to the output image + public WernerPaletteQuantizer(IErrorDiffuser diffuser) + : base(diffuser) + { + } + + /// + public override IFrameQuantizer CreateFrameQuantizer() + => this.CreateFrameQuantizer(NamedColors.WernerPalette.Length); + + /// + public override IFrameQuantizer CreateFrameQuantizer(int maxColors) + => this.CreateFrameQuantizer(NamedColors.WernerPalette, maxColors); + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs index 5123e737d3..629f7a2385 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs @@ -14,11 +14,6 @@ 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. /// @@ -41,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Whether to apply dithering to the output image public WuQuantizer(bool dither) - : this(GetDiffuser(dither), DefaultMaxColors) + : this(GetDiffuser(dither), QuantizerConstants.MaxColors) { } @@ -50,7 +45,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, DefaultMaxColors) + : this(diffuser, QuantizerConstants.MaxColors) { } @@ -62,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public WuQuantizer(IErrorDiffuser diffuser, int maxColors) { this.Diffuser = diffuser; - this.MaxColors = maxColors.Clamp(1, DefaultMaxColors); + this.MaxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); } /// @@ -82,7 +77,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public IFrameQuantizer CreateFrameQuantizer(int maxColors) where TPixel : struct, IPixel { - maxColors = maxColors.Clamp(1, DefaultMaxColors); + maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); return new WuFrameQuantizer(this, maxColors); } diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs index 12e74ccdbb..89eb63d629 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs public void GifCore() { // Try to get as close to System.Drawing's output as possible - var options = new GifEncoder { Quantizer = new PaletteQuantizer(false) }; + var options = new GifEncoder { Quantizer = new WebSafePaletteQuantizer(false) }; using (var memoryStream = new MemoryStream()) { this.bmpCore.SaveAsGif(memoryStream, options); diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs index 9b94347f34..bf9627f4c1 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs this.ForEachImageSharpImage((img, ms) => { // Try to get as close to System.Drawing's output as possible - var options = new GifEncoder { Quantizer = new PaletteQuantizer(false) }; + var options = new GifEncoder { Quantizer = new WebSafePaletteQuantizer(false) }; img.Save(ms, options); return null; }); } diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs index 962b34eb7c..639d1594ee 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs { using (var memoryStream = new MemoryStream()) { - var options = new PngEncoder { Quantizer = KnownQuantizers.Palette }; + var options = new PngEncoder { Quantizer = KnownQuantizers.WebSafe }; this.bmpCore.SaveAsPng(memoryStream, options); } } @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs { using (var memoryStream = new MemoryStream()) { - var options = new PngEncoder { Quantizer = new PaletteQuantizer(false) }; + var options = new PngEncoder { Quantizer = new WebSafePaletteQuantizer(false) }; this.bmpCore.SaveAsPng(memoryStream, options); } } diff --git a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs index 1d21c65fda..158a085d5a 100644 --- a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs +++ b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs @@ -67,7 +67,8 @@ namespace SixLabors.ImageSharp.Tests new TheoryData { nameof(KnownQuantizers.Octree), - nameof(KnownQuantizers.Palette), + nameof(KnownQuantizers.WebSafe), + nameof(KnownQuantizers.Werner), nameof(KnownQuantizers.Wu) }; diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index c5c971962c..a98ae164a1 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif { // Use the palette quantizer without dithering to ensure results // are consistant - Quantizer = new PaletteQuantizer(false) + Quantizer = new WebSafePaletteQuantizer(false) }; // Always save as we need to compare the encoded output. diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index c2b1c26c54..fb32522c9c 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -13,15 +13,18 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void QuantizersDitherByDefault() { - var palette = new PaletteQuantizer(); + var werner = new WernerPaletteQuantizer(); + var websafe = new WebSafePaletteQuantizer(); var octree = new OctreeQuantizer(); var wu = new WuQuantizer(); - Assert.NotNull(palette.Diffuser); + Assert.NotNull(werner.Diffuser); + Assert.NotNull(websafe.Diffuser); Assert.NotNull(octree.Diffuser); Assert.NotNull(wu.Diffuser); - Assert.True(palette.CreateFrameQuantizer().Dither); + Assert.True(werner.CreateFrameQuantizer().Dither); + Assert.True(websafe.CreateFrameQuantizer().Dither); Assert.True(octree.CreateFrameQuantizer().Dither); Assert.True(wu.CreateFrameQuantizer().Dither); } @@ -36,7 +39,7 @@ namespace SixLabors.ImageSharp.Tests { Assert.True(image[0, 0].Equals(default(TPixel))); - var quantizer = new PaletteQuantizer(dither); + var quantizer = new WebSafePaletteQuantizer(dither); foreach (ImageFrame frame in image.Frames) { From 0f538ff1953b637d01f6c913b068cad763cd9152 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 20 Oct 2018 14:42:23 +0200 Subject: [PATCH 175/381] fixed benchmarks and optimized implementation --- .../Helpers/SimdUtils.ExtendedIntrinsics.cs | 61 +++--- .../Color/Bulk/PackFromVector4.cs | 67 +++--- .../Color/Bulk/ToVector4.cs | 197 +++++++++++++++--- .../General/Vectorization/UInt32ToSingle.cs | 52 +++-- .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 6 +- 5 files changed, 279 insertions(+), 104 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index 6def8938a9..3131f18738 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -39,9 +39,8 @@ namespace SixLabors.ImageSharp ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); - ref Vector destBaseU = ref Unsafe.As, Vector>(ref destBase); - const float Scale = 1f / 255f; + var scale = new Vector(1f / 255f); for (int i = 0; i < n; i++) { @@ -51,26 +50,28 @@ namespace SixLabors.ImageSharp Vector.Widen(s0, out Vector w0, out Vector w1); Vector.Widen(s1, out Vector w2, out Vector w3); - ref Vector d = ref Unsafe.Add(ref destBaseU, i * 4); - d = w0; - Unsafe.Add(ref d, 1) = w1; - Unsafe.Add(ref d, 2) = w2; - Unsafe.Add(ref d, 3) = w3; - } - - n = dest.Length / Vector.Count; + Vector f0 = ConvertToSingle(w0, scale); + Vector f1 = ConvertToSingle(w1, scale); + Vector f2 = ConvertToSingle(w2, scale); + Vector f3 = ConvertToSingle(w3, scale); - for (int i = 0; i < n; i++) - { - ref Vector df = ref Unsafe.Add(ref destBase, i); - ref Vector du = ref Unsafe.As, Vector>(ref df); - - Vector v = Vector.ConvertToSingle(du); - v *= Scale; - df = v; + ref Vector d = ref Unsafe.Add(ref destBase, i * 4); + d = f0; + Unsafe.Add(ref d, 1) = f1; + Unsafe.Add(ref d, 2) = f2; + Unsafe.Add(ref d, 3) = f3; } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector ConvertToSingle(Vector u, Vector scale) + { + Vector vi = Vector.AsVectorInt32(u); + Vector v = Vector.ConvertToSingle(vi); + v *= scale; + return v; + } + /// /// A variant of , which is faster on new .NET runtime. /// @@ -92,26 +93,21 @@ namespace SixLabors.ImageSharp ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + Vector scale = new Vector(255); + for (int i = 0; i < n; i++) { ref Vector s = ref Unsafe.Add(ref sourceBase, i * 4); Vector f0 = s; - f0 = Clamp(f0); - Vector f1 = Unsafe.Add(ref s, 1); - f1 = Clamp(f1); - Vector f2 = Unsafe.Add(ref s, 2); - f2 = Clamp(f2); - Vector f3 = Unsafe.Add(ref s, 3); - f3 = Clamp(f3); - Vector w0 = Vector.ConvertToUInt32(f0 * 255f); - Vector w1 = Vector.ConvertToUInt32(f1 * 255f); - Vector w2 = Vector.ConvertToUInt32(f2 * 255f); - Vector w3 = Vector.ConvertToUInt32(f3 * 255f); + Vector w0 = ConvertToUInt32(f0, scale); + Vector w1 = ConvertToUInt32(f1, scale); + Vector w2 = ConvertToUInt32(f2, scale); + Vector w3 = ConvertToUInt32(f3, scale); Vector u0 = Vector.Narrow(w0, w1); Vector u1 = Vector.Narrow(w2, w3); @@ -123,9 +119,12 @@ namespace SixLabors.ImageSharp } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector Clamp(Vector x) + private static Vector ConvertToUInt32(Vector vf, Vector scale) { - return Vector.Min(Vector.Max(x, Vector.Zero), Vector.One); + vf = Vector.Min(Vector.Max(vf, Vector.Zero), Vector.One); + vf *= scale; + Vector vi = Vector.ConvertToInt32(vf); + return Vector.AsVectorUInt32(vi); } } } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index fb505ddcbd..1153d8f401 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -26,7 +26,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Params( //64, - 2048)] + 2048 + )] public int Count { get; set; } [GlobalSetup] @@ -43,7 +44,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.source.Dispose(); } - [Benchmark] + //[Benchmark] public void PerElement() { ref Vector4 s = ref MemoryMarshal.GetReference(this.source.GetSpan()); @@ -55,14 +56,14 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - [Benchmark(Baseline = true)] - public void CommonBulk() + [Benchmark] + public void PixelOperations_Base() { new PixelOperations().PackFromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } [Benchmark] - public void OptimizedBulk() + public void PixelOperations_Specialized() { PixelOperations.Instance.PackFromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } @@ -70,7 +71,30 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk public class PackFromVector4_Rgba32 : PackFromVector4 { - //[Benchmark] + [Benchmark] + public void FastDefault() + { + ref Vector4 sBase = ref this.source.GetSpan()[0]; + ref Rgba32 dBase = ref this.destination.GetSpan()[0]; + + Vector4 maxBytes = new Vector4(255); + Vector4 half = new Vector4(0.5f); + + for (int i = 0; i < this.Count; i++) + { + Vector4 v = Unsafe.Add(ref sBase, i); + v *= maxBytes; + v += half; + v = Vector4.Clamp(v, Vector4.Zero, maxBytes); + ref Rgba32 d = ref Unsafe.Add(ref dBase, i); + d.R = (byte)v.X; + d.G = (byte)v.Y; + d.B = (byte)v.Z; + d.A = (byte)v.W; + } + } + + [Benchmark(Baseline = true)] public void BulkConvertNormalizedFloatToByteClampOverflows() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); @@ -88,29 +112,16 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); } - // TODO: Check again later! // RESULTS: - // - // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 - // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores - // Frequency=2742187 Hz, Resolution=364.6724 ns, Timer=TSC - // .NET Core SDK=2.1.400-preview-009063 - // [Host] : .NET Core 2.1.1 (CoreCLR 4.6.26606.02, CoreFX 4.6.26606.05), 64bit RyuJIT - // Job-XIFINS : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 - // Job-RTQZPN : .NET Core 2.1.1 (CoreCLR 4.6.26606.02, CoreFX 4.6.26606.05), 64bit RyuJIT - // - // LaunchCount=1 TargetCount=3 WarmupCount=3 + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Allocated | + // ----------------------------------------------------------------- |-------- |------ |----------:|----------:|----------:|-------:|---------:|----------:| + // FastDefault | Clr | 2048 | 15.989 us | 6.1384 us | 0.3468 us | 4.07 | 0.08 | 0 B | + // BulkConvertNormalizedFloatToByteClampOverflows | Clr | 2048 | 3.931 us | 0.6264 us | 0.0354 us | 1.00 | 0.00 | 0 B | + // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 2048 | 2.100 us | 0.4717 us | 0.0267 us | 0.53 | 0.01 | 0 B | // - // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Allocated | - // ----------------------------------------------------------------- |-------- |------ |----------:|-----------:|----------:|-------:|---------:|----------:| - // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 2048 | 3.755 us | 0.8959 us | 0.0506 us | 0.22 | 0.00 | 0 B | - // PerElement | Clr | 2048 | 17.387 us | 15.1569 us | 0.8564 us | 1.02 | 0.04 | 0 B | - // CommonBulk | Clr | 2048 | 17.121 us | 0.7634 us | 0.0431 us | 1.00 | 0.00 | 24 B | - // OptimizedBulk | Clr | 2048 | 4.018 us | 0.3858 us | 0.0218 us | 0.23 | 0.00 | 0 B | - // | | | | | | | | | - // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Core | 2048 | 22.232 us | 1.6154 us | 0.0913 us | 1.31 | 0.04 | 0 B | - // PerElement | Core | 2048 | 16.741 us | 2.9254 us | 0.1653 us | 0.98 | 0.03 | 0 B | - // CommonBulk | Core | 2048 | 17.022 us | 11.4894 us | 0.6492 us | 1.00 | 0.00 | 24 B | - // OptimizedBulk | Core | 2048 | 3.707 us | 0.1500 us | 0.0085 us | 0.22 | 0.01 | 0 B | + // | | | | | | | | | + // FastDefault | Core | 2048 | 14.693 us | 0.5131 us | 0.0290 us | 3.76 | 0.03 | 0 B | + // BulkConvertNormalizedFloatToByteClampOverflows | Core | 2048 | 3.913 us | 0.5661 us | 0.0320 us | 1.00 | 0.00 | 0 B | + // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Core | 2048 | 1.966 us | 0.4056 us | 0.0229 us | 0.50 | 0.01 | 0 B | } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 6afd3cf6b1..d699d168bb 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -29,8 +29,9 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Params( //64, - //512 - 256 + //256, + //512, + 2048 )] public int Count { get; set; } @@ -60,70 +61,214 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - //[Benchmark] - public void CommonBulk() + [Benchmark] + public void PixelOperations_Base() { new PixelOperations().ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } - //[Benchmark] - public void OptimizedBulk() + [Benchmark] + public void PixelOperations_Specialized() { PixelOperations.Instance.ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } } - [RyuJitX64Job] - [DisassemblyDiagnoser(printAsm: true, printSource: true)] + [Config(typeof(Config.ShortClr))] public class ToVector4_Rgba32 : ToVector4 { - class Config : ManualConfig - { - } - - [Benchmark(Baseline = true)] - public void FastScalarBulk() + [Benchmark] + public void BasicBulk() { ref Rgba32 sBase = ref this.source.GetSpan()[0]; ref Vector4 dBase = ref this.destination.GetSpan()[0]; + Vector4 scale = new Vector4(1f / 255f); + + Vector4 v = default; + for (int i = 0; i < this.Count; i++) { ref Rgba32 s = ref Unsafe.Add(ref sBase, i); - ref Vector4 d = ref Unsafe.Add(ref dBase, i); - d.X = s.R; - d.Y = s.G; - d.Z = s.B; - d.W = s.A; + v.X = s.R; + v.Y = s.G; + v.Z = s.B; + v.W = s.A; + v *= scale; + Unsafe.Add(ref dBase, i) = v; + } + } + + [Benchmark(Baseline = true)] + public void BulkConvertByteToNormalizedFloat_2Loops() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + var bVec = new Vector(256.0f / 255.0f); + var magicFloat = new Vector(32768.0f); + var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f + var mask = new Vector(255); + + ref SimdUtils.Octet.OfByte sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); + ref SimdUtils.Octet.OfUInt32 destBaseAsWideOctet = ref Unsafe.As(ref MemoryMarshal.GetReference(dFloats)); + + ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsWideOctet); + + int n = dFloats.Length / 8; + + for (int i = 0; i < n; i++) + { + ref SimdUtils.Octet.OfByte s = ref Unsafe.Add(ref sourceBase, i); + ref SimdUtils.Octet.OfUInt32 d = ref Unsafe.Add(ref destBaseAsWideOctet, i); + d.LoadFrom(ref s); + } + + for (int i = 0; i < n; i++) + { + ref Vector df = ref Unsafe.Add(ref destBaseAsFloat, i); + + var vi = Vector.AsVectorUInt32(df); + vi &= mask; + vi |= magicInt; + + var vf = Vector.AsVectorSingle(vi); + vf = (vf - magicFloat) * bVec; + + df = vf; + } + } + + //[Benchmark] + public void BulkConvertByteToNormalizedFloat_ConvertInSameLoop() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + var bVec = new Vector(256.0f / 255.0f); + var magicFloat = new Vector(32768.0f); + var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f + var mask = new Vector(255); + + ref SimdUtils.Octet.OfByte sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); + ref SimdUtils.Octet.OfUInt32 destBaseAsWideOctet = ref Unsafe.As(ref MemoryMarshal.GetReference(dFloats)); + + ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsWideOctet); + + int n = dFloats.Length / 8; + + var temp = default(SimdUtils.Octet.OfUInt32); + ref Vector tempRef = ref Unsafe.As>(ref temp); + + for (int i = 0; i < n; i++) + { + ref SimdUtils.Octet.OfByte s = ref Unsafe.Add(ref sourceBase, i); + temp.LoadFrom(ref s); + + Vector vi = tempRef; + + vi &= mask; + vi |= magicInt; + + var vf = Vector.AsVectorSingle(vi); + vf = (vf - magicFloat) * bVec; + + Unsafe.Add(ref destBaseAsFloat, i) = vf; } } [Benchmark] - public void BulkConvertByteToNormalizedFloat() + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - SimdUtils.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + int n = dFloats.Length / Vector.Count; + + ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dFloats)); + ref Vector destBaseU = ref Unsafe.As, Vector>(ref destBase); + + for (int i = 0; i < n; i++) + { + Vector b = Unsafe.Add(ref sourceBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + ref Vector d = ref Unsafe.Add(ref destBaseU, i * 4); + d = w0; + Unsafe.Add(ref d, 1) = w1; + Unsafe.Add(ref d, 2) = w2; + Unsafe.Add(ref d, 3) = w3; + } + + n = dFloats.Length / Vector.Count; + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + ref Vector dRef = ref Unsafe.Add(ref destBase, i); + + Vector du = Vector.AsVectorInt32(dRef); + Vector v = Vector.ConvertToSingle(du); + v *= scale; + + dRef = v; + } } [Benchmark] - public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat() + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_ConvertInSameLoop() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + int n = dFloats.Length / Vector.Count; + + ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dFloats)); + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + Vector b = Unsafe.Add(ref sourceBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + Vector f0 = ConvertToNormalizedSingle(w0, scale); + Vector f1 = ConvertToNormalizedSingle(w1, scale); + Vector f2 = ConvertToNormalizedSingle(w2, scale); + Vector f3 = ConvertToNormalizedSingle(w3, scale); + + ref Vector d = ref Unsafe.Add(ref destBase, i * 4); + d = f0; + Unsafe.Add(ref d, 1) = f1; + Unsafe.Add(ref d, 2) = f2; + Unsafe.Add(ref d, 3) = f3; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector ConvertToNormalizedSingle(Vector u, Vector scale) + { + Vector vi = Vector.AsVectorInt32(u); + Vector v = Vector.ConvertToSingle(vi); + v *= scale; + return v; } //[Benchmark] - public void Original() + public void OldImplementation() { - ToVector4SimdAligned(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + ToVector4OldImplementation(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ToVector4SimdAligned(ReadOnlySpan sourceColors, Span destVectors, int count) + private static void ToVector4OldImplementation(ReadOnlySpan sourceColors, Span destVectors, int count) { if (!Vector.IsHardwareAccelerated) { diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs index 4a4b939b65..be19e719a8 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization { private float[] data; - private const int Count = 64; + private const int Count = 32; [GlobalSetup] public void Setup() @@ -24,8 +24,10 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization int n = Count / Vector.Count; - Vector magick = new Vector(32768.0f); - Vector scale = new Vector(255f) / new Vector(256f); + var bVec = new Vector(256.0f / 255.0f); + var magicFloat = new Vector(32768.0f); + var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f + var mask = new Vector(255); for (int i = 0; i < n; i++) { @@ -33,13 +35,16 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization // u.f = 32768.0f + x * (255.0f / 256.0f); // return (uint8_t)u.i; - ref Vector d = ref Unsafe.Add(ref b, i); - Vector x = d; - //x = Vector.Max(x, Vector.Zero); - //x = Vector.Min(x, Vector.One); + ref Vector df = ref Unsafe.Add(ref b, i); + + var vi = Vector.AsVectorUInt32(df); + vi &= mask; + vi |= magicInt; + + var vf = Vector.AsVectorSingle(vi); + vf = (vf - magicFloat) * bVec; - x = (x * scale) + magick; - d = x; + df = vf; } } @@ -48,18 +53,37 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization { int n = Count / Vector.Count; - ref Vector b = ref Unsafe.As>(ref this.data[0]); + ref Vector bf = ref Unsafe.As>(ref this.data[0]); + ref Vector bu = ref Unsafe.As, Vector>(ref bf); var scale = new Vector(1f / 255f); for (int i = 0; i < n; i++) { - ref Vector df = ref Unsafe.Add(ref b, i); - Vector du = Unsafe.As, Vector>(ref df); + Vector u = Unsafe.Add(ref bu, i); + Vector v = Vector.ConvertToSingle(u); + v *= scale; + Unsafe.Add(ref bf, i) = v; + } + } - Vector v = Vector.ConvertToSingle(du); + // This code is not correct at all, it's just here as reference + [Benchmark] + public void StandardSimdFromInt() + { + int n = Count / Vector.Count; + + ref Vector bf = ref Unsafe.As>(ref this.data[0]); + ref Vector bu = ref Unsafe.As, Vector>(ref bf); + + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + Vector u = Unsafe.Add(ref bu, i); + Vector v = Vector.ConvertToSingle(u); v *= scale; - df = v; + Unsafe.Add(ref bf, i) = v; } } } diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index 4b23ca30f1..7ed18ef86b 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -212,15 +212,11 @@ namespace SixLabors.ImageSharp.Tests.Common [InlineData(3, 128)] public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat(int seed, int count) { - if (!Vector.IsHardwareAccelerated) - { - return; - } - byte[] source = new Random(seed).GenerateRandomByteArray(count); float[] result = new float[count]; float[] expected = source.Select(b => (float)b / 255f).ToArray(); + SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(source, result); Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); From 664d838291b5fc0aa3b975c7749023c69ebc8258 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 20 Oct 2018 19:47:08 +0200 Subject: [PATCH 176/381] fix accuracy issues --- .../Helpers/SimdUtils.ExtendedIntrinsics.cs | 20 +++--- .../PixelFormats/Rgba32.PixelOperations.cs | 57 +++++++++++---- .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 70 +++++++++---------- .../TestUtilities/TestDataGenerator.cs | 9 +-- 4 files changed, 91 insertions(+), 65 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index 3131f18738..ec91e50988 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp { Guard.IsTrue( dest.Length % Vector.Count == 0, - nameof(source), + nameof(dest), "dest.Length should be divisable by Vector.Count!"); int n = dest.Length / Vector.Count; @@ -93,8 +93,6 @@ namespace SixLabors.ImageSharp ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); - Vector scale = new Vector(255); - for (int i = 0; i < n; i++) { ref Vector s = ref Unsafe.Add(ref sourceBase, i * 4); @@ -104,10 +102,10 @@ namespace SixLabors.ImageSharp Vector f2 = Unsafe.Add(ref s, 2); Vector f3 = Unsafe.Add(ref s, 3); - Vector w0 = ConvertToUInt32(f0, scale); - Vector w1 = ConvertToUInt32(f1, scale); - Vector w2 = ConvertToUInt32(f2, scale); - Vector w3 = ConvertToUInt32(f3, scale); + Vector w0 = ConvertToUInt32(f0); + Vector w1 = ConvertToUInt32(f1); + Vector w2 = ConvertToUInt32(f2); + Vector w3 = ConvertToUInt32(f3); Vector u0 = Vector.Narrow(w0, w1); Vector u1 = Vector.Narrow(w2, w3); @@ -119,10 +117,12 @@ namespace SixLabors.ImageSharp } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector ConvertToUInt32(Vector vf, Vector scale) + private static Vector ConvertToUInt32(Vector vf) { - vf = Vector.Min(Vector.Max(vf, Vector.Zero), Vector.One); - vf *= scale; + Vector maxBytes = new Vector(255f); + vf *= maxBytes; + vf += new Vector(0.5f); + vf = Vector.Min(Vector.Max(vf, Vector.Zero), maxBytes); Vector vi = Vector.ConvertToInt32(vf); return Vector.AsVectorUInt32(vi); } diff --git a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs index 0b96a599b6..bfef60c606 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs @@ -52,22 +52,13 @@ namespace SixLabors.ImageSharp.PixelFormats return; } - int remainder = count % 2; - int alignedCount = count - remainder; - - if (alignedCount > 0) + if (SimdUtils.ExtendedIntrinsics.IsAvailable) { - ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceVectors.Slice(0, alignedCount)); - Span rawDest = MemoryMarshal.Cast(destinationColors); - - SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(rawSrc, rawDest); + ConvertFromVector4ExtendedIntrinsics(sourceVectors, destinationColors, count); } - - if (remainder > 0) + else { - // actually: remainder == 1 - int lastIdx = count - 1; - destinationColors[lastIdx].PackFromVector4(sourceVectors[lastIdx]); + ConvertFromVector4StandardIntrinsics(sourceVectors, destinationColors, count); } } @@ -144,6 +135,46 @@ namespace SixLabors.ImageSharp.PixelFormats destinationVectors[lastIdx] = sourceColors[lastIdx].ToVector4(); } } + + private static void ConvertFromVector4ExtendedIntrinsics(ReadOnlySpan sourceVectors, Span destinationColors, int count) + { + int remainder = count % 8; + int alignedCount = count - remainder; + + if (alignedCount > 0) + { + ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceVectors); + Span rawDest = MemoryMarshal.Cast(destinationColors.Slice(0, alignedCount)); + + SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(rawSrc, rawDest); + } + + if (remainder > 0) + { + PackFromVector4Common(sourceVectors.Slice(alignedCount), destinationColors.Slice(alignedCount), remainder); + } + } + + private static void ConvertFromVector4StandardIntrinsics(ReadOnlySpan sourceVectors, Span destinationColors, int count) + { + int remainder = count % 2; + int alignedCount = count - remainder; + + if (alignedCount > 0) + { + ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceVectors.Slice(0, alignedCount)); + Span rawDest = MemoryMarshal.Cast(destinationColors); + + SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(rawSrc, rawDest); + } + + if (remainder > 0) + { + // actually: remainder == 1 + int lastIdx = count - 1; + destinationColors[lastIdx].PackFromVector4(sourceVectors[lastIdx]); + } + } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index 7ed18ef86b..4e1717bda9 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -160,31 +160,6 @@ namespace SixLabors.ImageSharp.Tests.Common Assert.Equal(expected, dest); } - private static float Clamp255(float x) => Math.Min(255f, Math.Max(0f, x)); - - [Theory] - [InlineData(1, 0)] - [InlineData(1, 8)] - [InlineData(2, 16)] - [InlineData(3, 128)] - public void BulkConvertNormalizedFloatToByteClampOverflows(int seed, int count) - { - if (this.SkipOnNonAvx2()) - { - return; - } - - float[] orig = new Random(seed).GenerateRandomRoundedFloatArray(count, -50, 444); - float[] normalized = orig.Select(f => f / 255f).ToArray(); - - byte[] dest = new byte[count]; - - SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(normalized, dest); - - byte[] expected = orig.Select(f => (byte)Clamp255(f)).ToArray(); - - Assert.Equal(expected, dest); - } [Theory] [InlineData(1, 0)] @@ -222,23 +197,44 @@ namespace SixLabors.ImageSharp.Tests.Common Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); } + + public static readonly TheoryData BulkConvertNormalizedFloatToByteClampOverflows_Data = + new TheoryData + { + 0, 64, 1024 + }; + [Theory] - [InlineData(1, 0)] - [InlineData(2, 32)] - [InlineData(3, 128)] - public void ExtendedIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int seed, int count) + [MemberData(nameof(BulkConvertNormalizedFloatToByteClampOverflows_Data))] + public void BulkConvertNormalizedFloatToByteClampOverflows(int count) { - float[] orig = new Random(seed).GenerateRandomRoundedFloatArray(count, -50, 444); - float[] normalized = orig.Select(f => f / 255f).ToArray(); + if (this.SkipOnNonAvx2()) + { + return; + } - byte[] dest = new byte[count]; + float[] source = new Random(count).GenerateRandomFloatArray(count, -0.1f, 1.2f); + byte[] expected = source.Select(NormalizedFloatToByte).ToArray(); + byte[] actual = new byte[count]; - SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(normalized, dest); + SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(source, actual); - byte[] expected = orig.Select(f => (byte)Clamp255(f)).ToArray(); + Assert.Equal(expected, actual); + } - Assert.Equal(expected, dest); + [Theory] + [MemberData(nameof(BulkConvertNormalizedFloatToByteClampOverflows_Data))] + public void ExtendedIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int count) + { + float[] source = new Random(count).GenerateRandomFloatArray(count, -0.1f, 1.2f); + byte[] expected = source.Select(NormalizedFloatToByte).ToArray(); + byte[] actual = new byte[count]; + + SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(source, actual); + + Assert.Equal(expected, actual); } + private static byte NormalizedFloatToByte(float f) => (byte)Math.Min(255f, Math.Max(0f, f * 255f + 0.5f)); [Theory] [InlineData(0)] @@ -265,7 +261,7 @@ namespace SixLabors.ImageSharp.Tests.Common float[] source = { 0, 7, 42, 255, 0.5f, 1.1f, 2.6f, 16f }; - var expected = source.Select(f => (byte)Math.Round(f)).ToArray(); + byte[] expected = source.Select(f => (byte)Math.Round(f)).ToArray(); source = source.Select(f => f / 255f).ToArray(); @@ -299,8 +295,6 @@ namespace SixLabors.ImageSharp.Tests.Common iiRef = x; - //Tuple8.OfUInt32 ii = Unsafe.As, Tuple8.OfUInt32>(ref x); - ref Tuple8.OfByte d = ref MemoryMarshal.Cast(dest)[0]; d.LoadFrom(ref ii); diff --git a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs index 6f3b18e1fc..912b86e347 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs @@ -33,19 +33,20 @@ namespace SixLabors.ImageSharp.Tests return values; } - public static float[] GenerateRandomRoundedFloatArray(this Random rnd, int length, int minVal, int maxValExclusive) + public static float[] GenerateRandomRoundedFloatArray(this Random rnd, int length, float minVal, float maxVal) { float[] values = new float[length]; for (int i = 0; i < length; i++) { - int val = rnd.Next(minVal, maxValExclusive); - values[i] = (float)val; + values[i] = (float) Math.Round(rnd.GetRandomFloat(minVal, maxVal)); } return values; } + + public static byte[] GenerateRandomByteArray(this Random rnd, int length) { byte[] values = new byte[length]; @@ -53,7 +54,7 @@ namespace SixLabors.ImageSharp.Tests return values; } - private static float GetRandomFloat(Random rnd, float minVal, float maxVal) + private static float GetRandomFloat(this Random rnd, float minVal, float maxVal) { return (float)rnd.NextDouble() * (maxVal - minVal) + minVal; } From 10afe6572e598274e89ba8851b87732eb2f6d6fc Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 20 Oct 2018 20:05:20 +0200 Subject: [PATCH 177/381] cleanup benchmarks --- .../Color/Bulk/ToVector4.cs | 96 ++----------------- 1 file changed, 10 insertions(+), 86 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index d699d168bb..726e214a96 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -100,84 +100,24 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark(Baseline = true)] - public void BulkConvertByteToNormalizedFloat_2Loops() + public void BulkConvertByteToNormalizedFloat() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - var bVec = new Vector(256.0f / 255.0f); - var magicFloat = new Vector(32768.0f); - var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f - var mask = new Vector(255); - - ref SimdUtils.Octet.OfByte sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); - ref SimdUtils.Octet.OfUInt32 destBaseAsWideOctet = ref Unsafe.As(ref MemoryMarshal.GetReference(dFloats)); - - ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsWideOctet); - - int n = dFloats.Length / 8; - - for (int i = 0; i < n; i++) - { - ref SimdUtils.Octet.OfByte s = ref Unsafe.Add(ref sourceBase, i); - ref SimdUtils.Octet.OfUInt32 d = ref Unsafe.Add(ref destBaseAsWideOctet, i); - d.LoadFrom(ref s); - } - - for (int i = 0; i < n; i++) - { - ref Vector df = ref Unsafe.Add(ref destBaseAsFloat, i); - - var vi = Vector.AsVectorUInt32(df); - vi &= mask; - vi |= magicInt; - - var vf = Vector.AsVectorSingle(vi); - vf = (vf - magicFloat) * bVec; - - df = vf; - } + SimdUtils.BulkConvertByteToNormalizedFloat(sBytes, dFloats); } - //[Benchmark] - public void BulkConvertByteToNormalizedFloat_ConvertInSameLoop() + [Benchmark] + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - var bVec = new Vector(256.0f / 255.0f); - var magicFloat = new Vector(32768.0f); - var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f - var mask = new Vector(255); - - ref SimdUtils.Octet.OfByte sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); - ref SimdUtils.Octet.OfUInt32 destBaseAsWideOctet = ref Unsafe.As(ref MemoryMarshal.GetReference(dFloats)); - - ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsWideOctet); - - int n = dFloats.Length / 8; - - var temp = default(SimdUtils.Octet.OfUInt32); - ref Vector tempRef = ref Unsafe.As>(ref temp); - - for (int i = 0; i < n; i++) - { - ref SimdUtils.Octet.OfByte s = ref Unsafe.Add(ref sourceBase, i); - temp.LoadFrom(ref s); - - Vector vi = tempRef; - - vi &= mask; - vi |= magicInt; - - var vf = Vector.AsVectorSingle(vi); - vf = (vf - magicFloat) * bVec; - - Unsafe.Add(ref destBaseAsFloat, i) = vf; - } + SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats); } - [Benchmark] + //[Benchmark] public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); @@ -219,7 +159,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - [Benchmark] + //[Benchmark] public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_ConvertInSameLoop() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); @@ -264,23 +204,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk //[Benchmark] public void OldImplementation() { - ToVector4OldImplementation(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ToVector4OldImplementation(ReadOnlySpan sourceColors, Span destVectors, int count) - { - if (!Vector.IsHardwareAccelerated) - { - throw new InvalidOperationException( - "Rgba32.PixelOperations.ToVector4SimdAligned() should not be called when Vector.IsHardwareAccelerated == false!"); - } - - DebugGuard.IsTrue( - count % Vector.Count == 0, - nameof(count), - "Argument 'count' should divisible by Vector.Count!"); - + int count = this.Count; var bVec = new Vector(256.0f / 255.0f); var magicFloat = new Vector(32768.0f); var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f @@ -288,8 +212,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk int unpackedRawCount = count * 4; - ref uint sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference(sourceColors)); - ref UnpackedRGBA destBaseAsUnpacked = ref Unsafe.As(ref MemoryMarshal.GetReference(destVectors)); + ref uint sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference((ReadOnlySpan)this.source.GetSpan())); + ref UnpackedRGBA destBaseAsUnpacked = ref Unsafe.As(ref MemoryMarshal.GetReference(this.destination.GetSpan())); ref Vector destBaseAsUInt = ref Unsafe.As>(ref destBaseAsUnpacked); ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsUnpacked); From 17f6dcc877f720848ca9d21a443c341c22bfaf87 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 20 Oct 2018 22:49:31 +0200 Subject: [PATCH 178/381] Bulk conversion of arbitrary-sized Span-s of scalars --- .../Helpers/SimdUtils.BasicIntrinsics256.cs | 212 +++++++++++++++ .../Helpers/SimdUtils.ExtendedIntrinsics.cs | 90 +++++-- src/ImageSharp/Common/Helpers/SimdUtils.cs | 255 +++--------------- src/ImageSharp/Common/Tuples/Octet.cs | 100 +++++++ src/ImageSharp/Common/Tuples/Vector4Pair.cs | 2 +- .../JpegColorConverter.FromYCbCrSimd.cs | 2 +- .../JpegColorConverter.FromYCbCrSimdAvx2.cs | 2 +- .../ColorConverters/JpegColorConverter.cs | 2 +- .../PixelFormats/Rgba32.PixelOperations.cs | 12 +- .../Color/Bulk/ToVector4.cs | 8 +- .../General/Vectorization/UInt32ToSingle.cs | 27 +- .../Vectorization/WidenBytesToUInt32.cs | 7 +- .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 108 +++++--- 13 files changed, 537 insertions(+), 290 deletions(-) create mode 100644 src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs create mode 100644 src/ImageSharp/Common/Tuples/Octet.cs diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs new file mode 100644 index 0000000000..e4dc1a1d8f --- /dev/null +++ b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs @@ -0,0 +1,212 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Diagnostics; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Tuples; + +// ReSharper disable MemberHidesStaticFromOuterClass +namespace SixLabors.ImageSharp +{ + internal static partial class SimdUtils + { + /// + /// 256bit / AVX2 intrinsics NOT depending on newer API-s (Vector.Widen, Vector.Narrow, Vector.ConvertTo*) + /// + public static class BasicIntrinsics256 + { + public static bool IsAvailable { get; } = IsAvx2CompatibleArchitecture; + + /// + /// as much elements as possible, slicing them down (keeping the remainder). + /// + internal static void BulkConvertByteToNormalizedFloatReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + + if (IsAvailable) + { + int remainder = source.Length % 8; + int alignedCount = source.Length - remainder; + + if (alignedCount > 0) + { + BulkConvertByteToNormalizedFloat( + source.Slice(0, alignedCount), + dest.Slice(0, alignedCount)); + + source = source.Slice(alignedCount); + dest = dest.Slice(alignedCount); + } + } + } + + /// + /// Convert 'source.Length' values normalized into [0..1] from 'source' + /// into 'dest' buffer of . The values are scaled up into [0-255] and rounded. + /// The implementation is SIMD optimized and works only with `source.Length` divisible by 8/>. + /// Based on: + /// + /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions + /// + /// + internal static void BulkConvertNormalizedFloatToByte(ReadOnlySpan source, Span dest) + { + GuardAvx2(nameof(BulkConvertNormalizedFloatToByte)); + + DebugGuard.IsTrue((source.Length % Vector.Count) == 0, nameof(source), "source.Length should be divisable by Vector.Count!"); + + if (source.Length == 0) + { + return; + } + + ref Vector srcBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Octet.OfByte destBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + int n = source.Length / 8; + + Vector magick = new Vector(32768.0f); + Vector scale = new Vector(255f) / new Vector(256f); + + // need to copy to a temporary struct, because + // SimdUtils.Octet.OfUInt32 temp = Unsafe.As, SimdUtils.Octet.OfUInt32>(ref x) + // does not work. TODO: This might be a CoreClr bug, need to ask/report + var temp = default(Octet.OfUInt32); + ref Vector tempRef = ref Unsafe.As>(ref temp); + + for (int i = 0; i < n; i++) + { + // union { float f; uint32_t i; } u; + // u.f = 32768.0f + x * (255.0f / 256.0f); + // return (uint8_t)u.i; + Vector x = Unsafe.Add(ref srcBase, i); + x = (x * scale) + magick; + tempRef = x; + + ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i); + d.LoadFrom(ref temp); + } + } + + /// + /// SIMD optimized implementation for . + /// Works only with `dest.Length` divisible by 8. + /// Implementation adapted from: + /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions + /// http://stackoverflow.com/a/536278 + /// + internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + { + GuardAvx2(nameof(BulkConvertByteToNormalizedFloat)); + + DebugGuard.IsTrue((dest.Length % 8) == 0, nameof(source), "dest.Length should be divisable by 8!"); + + var bVec = new Vector(256.0f / 255.0f); + var magicFloat = new Vector(32768.0f); + var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f + var mask = new Vector(255); + + ref Octet.OfByte sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref Octet.OfUInt32 destBaseAsWideOctet = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + + ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsWideOctet); + + int n = dest.Length / 8; + + for (int i = 0; i < n; i++) + { + ref Octet.OfByte s = ref Unsafe.Add(ref sourceBase, i); + ref Octet.OfUInt32 d = ref Unsafe.Add(ref destBaseAsWideOctet, i); + d.LoadFrom(ref s); + } + + for (int i = 0; i < n; i++) + { + ref Vector df = ref Unsafe.Add(ref destBaseAsFloat, i); + + var vi = Vector.AsVectorUInt32(df); + vi &= mask; + vi |= magicInt; + + var vf = Vector.AsVectorSingle(vi); + vf = (vf - magicFloat) * bVec; + + df = vf; + } + } + + /// + /// as much elements as possible, slicing them down (keeping the remainder). + /// + internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + + if (IsAvailable) + { + int remainder = source.Length % Vector.Count; + int alignedCount = source.Length - remainder; + + if (alignedCount > 0) + { + BulkConvertNormalizedFloatToByteClampOverflows(source.Slice(0, alignedCount), dest.Slice(0, alignedCount)); + + source = source.Slice(alignedCount); + dest = dest.Slice(alignedCount); + } + } + } + + /// + /// Same as but clamps overflown values before conversion. + /// + internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) + { + GuardAvx2(nameof(BulkConvertNormalizedFloatToByteClampOverflows)); + + DebugGuard.IsTrue((source.Length % 8) == 0, nameof(source), "source.Length should be divisible by 8!"); + + if (source.Length == 0) + { + return; + } + + ref Vector srcBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Octet.OfByte destBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + int n = source.Length / 8; + + Vector magick = new Vector(32768.0f); + Vector scale = new Vector(255f) / new Vector(256f); + + // need to copy to a temporary struct, because + // SimdUtils.Octet.OfUInt32 temp = Unsafe.As, SimdUtils.Octet.OfUInt32>(ref x) + // does not work. TODO: This might be a CoreClr bug, need to ask/report + var temp = default(Octet.OfUInt32); + ref Vector tempRef = ref Unsafe.As>(ref temp); + + for (int i = 0; i < n; i++) + { + // union { float f; uint32_t i; } u; + // u.f = 32768.0f + x * (255.0f / 256.0f); + // return (uint8_t)u.i; + Vector x = Unsafe.Add(ref srcBase, i); + x = Vector.Max(x, Vector.Zero); + x = Vector.Min(x, Vector.One); + + x = (x * scale) + magick; + tempRef = x; + + ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i); + d.LoadFrom(ref temp); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index ec91e50988..5c0b8ee93a 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -1,8 +1,10 @@ using System; +using System.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +// ReSharper disable MemberHidesStaticFromOuterClass namespace SixLabors.ImageSharp { internal static partial class SimdUtils @@ -18,22 +20,47 @@ namespace SixLabors.ImageSharp { public static bool IsAvailable { get; } = #if NETCOREAPP2_1 -// TODO: Also available in .NET 4.7.2, we need to add a build target! - true; + // TODO: Also available in .NET 4.7.2, we need to add a build target! + Vector.IsHardwareAccelerated; #else false; #endif /// - /// A variant of , which is faster on new .NET runtime. + /// as much elements as possible, slicing them down (keeping the remainder). + /// + [Conditional("NETCOREAPP2_1")] + internal static void BulkConvertByteToNormalizedFloatReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + + if (IsAvailable) + { + int remainder = source.Length % Vector.Count; + int alignedCount = source.Length - remainder; + + if (alignedCount > 0) + { + BulkConvertByteToNormalizedFloat(source.Slice(0, alignedCount), dest.Slice(0, alignedCount)); + + source = source.Slice(alignedCount); + dest = dest.Slice(alignedCount); + } + } + } + + /// + /// A variant of , which is faster on new RyuJIT runtime. /// // ReSharper disable once MemberHidesStaticFromOuterClass internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { - Guard.IsTrue( + DebugGuard.IsTrue( dest.Length % Vector.Count == 0, nameof(source), - "dest.Length should be divisable by Vector.Count!"); + "dest.Length should be divisible by Vector.Count!"); int n = dest.Length / Vector.Count; @@ -63,34 +90,52 @@ namespace SixLabors.ImageSharp } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector ConvertToSingle(Vector u, Vector scale) + /// + /// as much elements as possible, slicing them down (keeping the remainder). + /// + [Conditional("NETCOREAPP2_1")] + internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( + ref ReadOnlySpan source, + ref Span dest) { - Vector vi = Vector.AsVectorInt32(u); - Vector v = Vector.ConvertToSingle(vi); - v *= scale; - return v; + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + + if (IsAvailable) + { + int remainder = source.Length % Vector.Count; + int alignedCount = source.Length - remainder; + + if (alignedCount > 0) + { + BulkConvertNormalizedFloatToByteClampOverflows(source.Slice(0, alignedCount), dest.Slice(0, alignedCount)); + + source = source.Slice(alignedCount); + dest = dest.Slice(alignedCount); + } + } } /// - /// A variant of , which is faster on new .NET runtime. + /// A variant of , which is faster on new .NET runtime. /// /// /// It does NOT worth yet to utilize this method (2018 Oct). /// See benchmark results for the "PackFromVector4_Rgba32" benchmark! /// TODO: Check again later! /// - // ReSharper disable once MemberHidesStaticFromOuterClass - internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) + internal static void BulkConvertNormalizedFloatToByteClampOverflows( + ReadOnlySpan source, + Span dest) { - Guard.IsTrue( + DebugGuard.IsTrue( dest.Length % Vector.Count == 0, nameof(dest), - "dest.Length should be divisable by Vector.Count!"); + "dest.Length should be divisible by Vector.Count!"); int n = dest.Length / Vector.Count; - ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector sourceBase = + ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); for (int i = 0; i < n; i++) @@ -126,6 +171,15 @@ namespace SixLabors.ImageSharp Vector vi = Vector.ConvertToInt32(vf); return Vector.AsVectorUInt32(vi); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector ConvertToSingle(Vector u, Vector scale) + { + Vector vi = Vector.AsVectorInt32(u); + Vector v = Vector.ConvertToSingle(vi); + v *= scale; + return v; + } } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index 91aed8c79a..73e9bacfa8 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -6,6 +6,9 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tuples; + namespace SixLabors.ImageSharp { /// @@ -16,7 +19,8 @@ namespace SixLabors.ImageSharp /// /// Gets a value indicating whether the code is being executed on AVX2 CPU where both float and integer registers are of size 256 byte. /// - public static bool IsAvx2CompatibleArchitecture { get; } = Vector.IsHardwareAccelerated && Vector.Count == 8 && Vector.Count == 8; + public static bool IsAvx2CompatibleArchitecture { get; } = + Vector.IsHardwareAccelerated && Vector.Count == 8 && Vector.Count == 8; internal static void GuardAvx2(string operation) { @@ -57,236 +61,61 @@ namespace SixLabors.ImageSharp } /// - /// Convert 'source.Length' values normalized into [0..1] from 'source' into 'dest' buffer of values. - /// The values are scaled up into [0-255] and rounded. - /// The implementation is SIMD optimized and works only with `source.Length` divisible by . - /// Based on: - /// - /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions - /// - /// - internal static void BulkConvertNormalizedFloatToByte(ReadOnlySpan source, Span dest) - { - GuardAvx2(nameof(BulkConvertNormalizedFloatToByte)); - - DebugGuard.IsTrue((source.Length % Vector.Count) == 0, nameof(source), "source.Length should be divisable by Vector.Count!"); - - if (source.Length == 0) - { - return; - } - - ref Vector srcBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - ref Octet.OfByte destBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - int n = source.Length / 8; - - Vector magick = new Vector(32768.0f); - Vector scale = new Vector(255f) / new Vector(256f); - - // need to copy to a temporary struct, because - // SimdUtils.Octet.OfUInt32 temp = Unsafe.As, SimdUtils.Octet.OfUInt32>(ref x) - // does not work. TODO: This might be a CoreClr bug, need to ask/report - var temp = default(Octet.OfUInt32); - ref Vector tempRef = ref Unsafe.As>(ref temp); - - for (int i = 0; i < n; i++) - { - // union { float f; uint32_t i; } u; - // u.f = 32768.0f + x * (255.0f / 256.0f); - // return (uint8_t)u.i; - Vector x = Unsafe.Add(ref srcBase, i); - x = (x * scale) + magick; - tempRef = x; - - ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i); - d.LoadFrom(ref temp); - } - } - - /// - /// Converts `dest.Length` bytes to -s to -s normalized into [0..1] - /// The implementation is SIMD optimized and works only with `dest.Length` divisible by . - /// Implementation adapted from: - /// - /// http://stackoverflow.com/a/5362789 - /// + /// Converts `dest.Length` -s to -s normalized into [0..1]. + /// should be the of the same size as , + /// but there are no restrictions on the span's length. /// internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { - GuardAvx2(nameof(BulkConvertByteToNormalizedFloat)); - - DebugGuard.IsTrue((dest.Length % Vector.Count) == 0, nameof(source), "dest.Length should be divisable by Vector.Count!"); - - var bVec = new Vector(256.0f / 255.0f); - var magicFloat = new Vector(32768.0f); - var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f - var mask = new Vector(255); + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); - ref Octet.OfByte sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref Octet.OfUInt32 destBaseAsWideOctet = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - - ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsWideOctet); - - int n = dest.Length / 8; - - for (int i = 0; i < n; i++) - { - ref Octet.OfByte s = ref Unsafe.Add(ref sourceBase, i); - ref Octet.OfUInt32 d = ref Unsafe.Add(ref destBaseAsWideOctet, i); - d.LoadFrom(ref s); - } + ExtendedIntrinsics.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); + BasicIntrinsics256.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); - for (int i = 0; i < n; i++) + // Deal with the remainder: + int count = source.Length; + if (count > 0) { - ref Vector df = ref Unsafe.Add(ref destBaseAsFloat, i); - - var vi = Vector.AsVectorUInt32(df); - vi &= mask; - vi |= magicInt; - - var vf = Vector.AsVectorSingle(vi); - vf = (vf - magicFloat) * bVec; - - df = vf; + // TODO: Do we need to optimize anything on this? (There are at most 7 remainders) + ref byte sBase = ref MemoryMarshal.GetReference(source); + ref float dBase = ref MemoryMarshal.GetReference(dest); + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref dBase, i) = Unsafe.Add(ref sBase, i) / 255f; + } } } /// - /// Same as but clamps overflown values before conversion. + /// Convert 'source.Length' values normalized into [0..1] from 'source' into 'dest' buffer of . + /// The values are scaled up into [0-255] and rounded, overflows are clamped. + /// should be the of the same size as , + /// but there are no restrictions on the span's length. /// internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) { - GuardAvx2(nameof(BulkConvertNormalizedFloatToByteClampOverflows)); - - DebugGuard.IsTrue((source.Length % Vector.Count) == 0, nameof(source), "source.Length should be divisable by Vector.Count!"); - - if (source.Length == 0) - { - return; - } - - ref Vector srcBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - ref Octet.OfByte destBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - int n = source.Length / 8; - - Vector magick = new Vector(32768.0f); - Vector scale = new Vector(255f) / new Vector(256f); - - // need to copy to a temporary struct, because - // SimdUtils.Octet.OfUInt32 temp = Unsafe.As, SimdUtils.Octet.OfUInt32>(ref x) - // does not work. TODO: This might be a CoreClr bug, need to ask/report - var temp = default(Octet.OfUInt32); - ref Vector tempRef = ref Unsafe.As>(ref temp); - - for (int i = 0; i < n; i++) - { - // union { float f; uint32_t i; } u; - // u.f = 32768.0f + x * (255.0f / 256.0f); - // return (uint8_t)u.i; - Vector x = Unsafe.Add(ref srcBase, i); - x = Vector.Max(x, Vector.Zero); - x = Vector.Min(x, Vector.One); - - x = (x * scale) + magick; - tempRef = x; - - ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i); - d.LoadFrom(ref temp); - } - } - - // TODO: Replace these with T4-d library level tuples! - internal static class Octet - { - [StructLayout(LayoutKind.Explicit, Size = 8 * sizeof(uint))] - public struct OfUInt32 - { - [FieldOffset(0 * sizeof(uint))] - public uint V0; - - [FieldOffset(1 * sizeof(uint))] - public uint V1; - - [FieldOffset(2 * sizeof(uint))] - public uint V2; - - [FieldOffset(3 * sizeof(uint))] - public uint V3; - - [FieldOffset(4 * sizeof(uint))] - public uint V4; - - [FieldOffset(5 * sizeof(uint))] - public uint V5; + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); - [FieldOffset(6 * sizeof(uint))] - public uint V6; + ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); + BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); - [FieldOffset(7 * sizeof(uint))] - public uint V7; - - public override string ToString() - { - return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]"; - } - - [MethodImpl(InliningOptions.ShortMethod)] - public void LoadFrom(ref OfByte src) - { - this.V0 = src.V0; - this.V1 = src.V1; - this.V2 = src.V2; - this.V3 = src.V3; - this.V4 = src.V4; - this.V5 = src.V5; - this.V6 = src.V6; - this.V7 = src.V7; - } - } - - [StructLayout(LayoutKind.Explicit, Size = 8)] - public struct OfByte + // Deal with the remainder: + int count = source.Length; + if (count > 0) { - [FieldOffset(0)] - public byte V0; - - [FieldOffset(1)] - public byte V1; - - [FieldOffset(2)] - public byte V2; - - [FieldOffset(3)] - public byte V3; - - [FieldOffset(4)] - public byte V4; - - [FieldOffset(5)] - public byte V5; - - [FieldOffset(6)] - public byte V6; - - [FieldOffset(7)] - public byte V7; - - public override string ToString() - { - return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]"; - } + ref float sBase = ref MemoryMarshal.GetReference(source); + ref byte dBase = ref MemoryMarshal.GetReference(dest); - [MethodImpl(InliningOptions.ShortMethod)] - public void LoadFrom(ref OfUInt32 src) + for (int i = 0; i < count; i++) { - this.V0 = (byte)src.V0; - this.V1 = (byte)src.V1; - this.V2 = (byte)src.V2; - this.V3 = (byte)src.V3; - this.V4 = (byte)src.V4; - this.V5 = (byte)src.V5; - this.V6 = (byte)src.V6; - this.V7 = (byte)src.V7; + // TODO: Do we need to optimize anything on this? (There are at most 7 remainders) + float f = Unsafe.Add(ref sBase, i); + f *= 255f; + f += 0.5f; + f = MathF.Max(0, f); + f = MathF.Min(255f, f); + + Unsafe.Add(ref dBase, i) = (byte)f; } } } diff --git a/src/ImageSharp/Common/Tuples/Octet.cs b/src/ImageSharp/Common/Tuples/Octet.cs new file mode 100644 index 0000000000..ae01a31217 --- /dev/null +++ b/src/ImageSharp/Common/Tuples/Octet.cs @@ -0,0 +1,100 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.Tuples +{ + internal static class Octet + { + [StructLayout(LayoutKind.Explicit, Size = 8 * sizeof(uint))] + public struct OfUInt32 + { + [FieldOffset(0 * sizeof(uint))] + public uint V0; + + [FieldOffset(1 * sizeof(uint))] + public uint V1; + + [FieldOffset(2 * sizeof(uint))] + public uint V2; + + [FieldOffset(3 * sizeof(uint))] + public uint V3; + + [FieldOffset(4 * sizeof(uint))] + public uint V4; + + [FieldOffset(5 * sizeof(uint))] + public uint V5; + + [FieldOffset(6 * sizeof(uint))] + public uint V6; + + [FieldOffset(7 * sizeof(uint))] + public uint V7; + + public override string ToString() + { + return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]"; + } + + [MethodImpl(InliningOptions.ShortMethod)] + public void LoadFrom(ref OfByte src) + { + this.V0 = src.V0; + this.V1 = src.V1; + this.V2 = src.V2; + this.V3 = src.V3; + this.V4 = src.V4; + this.V5 = src.V5; + this.V6 = src.V6; + this.V7 = src.V7; + } + } + + [StructLayout(LayoutKind.Explicit, Size = 8)] + public struct OfByte + { + [FieldOffset(0)] + public byte V0; + + [FieldOffset(1)] + public byte V1; + + [FieldOffset(2)] + public byte V2; + + [FieldOffset(3)] + public byte V3; + + [FieldOffset(4)] + public byte V4; + + [FieldOffset(5)] + public byte V5; + + [FieldOffset(6)] + public byte V6; + + [FieldOffset(7)] + public byte V7; + + public override string ToString() + { + return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]"; + } + + [MethodImpl(InliningOptions.ShortMethod)] + public void LoadFrom(ref OfUInt32 src) + { + this.V0 = (byte)src.V0; + this.V1 = (byte)src.V1; + this.V2 = (byte)src.V2; + this.V3 = (byte)src.V3; + this.V4 = (byte)src.V4; + this.V5 = (byte)src.V5; + this.V6 = (byte)src.V6; + this.V7 = (byte)src.V7; + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Tuples/Vector4Pair.cs b/src/ImageSharp/Common/Tuples/Vector4Pair.cs index 309d5e2e56..5988b2200b 100644 --- a/src/ImageSharp/Common/Tuples/Vector4Pair.cs +++ b/src/ImageSharp/Common/Tuples/Vector4Pair.cs @@ -2,7 +2,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -namespace SixLabors.ImageSharp.Common.Tuples +namespace SixLabors.ImageSharp.Tuples { /// /// Its faster to process multiple Vector4-s together, so let's pair them! 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 4b2626c582..5c63a478db 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs @@ -6,7 +6,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Common.Tuples; +using SixLabors.ImageSharp.Tuples; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { 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 ab4947e65c..3f26cdc907 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs @@ -6,7 +6,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Common.Tuples; +using SixLabors.ImageSharp.Tuples; // ReSharper disable ImpureMethodCallOnReadonlyValueField namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs index 60abb7fb2c..293f3bc1f7 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs @@ -6,8 +6,8 @@ using System.Collections.Generic; using System.Linq; using System.Numerics; -using SixLabors.ImageSharp.Common.Tuples; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.Tuples; using SixLabors.Memory; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters diff --git a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs index bfef60c606..564b93ef52 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats } else { - ConvertToVector4UsingStandardIntrinsics(sourceColors, destinationVectors, count); + ConvertToVector4UsingBasicIntrinsics(sourceColors, destinationVectors, count); } } @@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.PixelFormats } else { - ConvertFromVector4StandardIntrinsics(sourceVectors, destinationColors, count); + ConvertFromVector4BasicIntrinsics(sourceVectors, destinationColors, count); } } @@ -112,7 +112,7 @@ namespace SixLabors.ImageSharp.PixelFormats } } - private static void ConvertToVector4UsingStandardIntrinsics( + private static void ConvertToVector4UsingBasicIntrinsics( ReadOnlySpan sourceColors, Span destinationVectors, int count) @@ -125,7 +125,7 @@ namespace SixLabors.ImageSharp.PixelFormats ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceColors); Span rawDest = MemoryMarshal.Cast(destinationVectors.Slice(0, alignedCount)); - SimdUtils.BulkConvertByteToNormalizedFloat(rawSrc, rawDest); + SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(rawSrc, rawDest); } if (remainder > 0) @@ -155,7 +155,7 @@ namespace SixLabors.ImageSharp.PixelFormats } } - private static void ConvertFromVector4StandardIntrinsics(ReadOnlySpan sourceVectors, Span destinationColors, int count) + private static void ConvertFromVector4BasicIntrinsics(ReadOnlySpan sourceVectors, Span destinationColors, int count) { int remainder = count % 2; int alignedCount = count - remainder; @@ -165,7 +165,7 @@ namespace SixLabors.ImageSharp.PixelFormats ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceVectors.Slice(0, alignedCount)); Span rawDest = MemoryMarshal.Cast(destinationColors); - SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(rawSrc, rawDest); + SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflows(rawSrc, rawDest); } if (remainder > 0) diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 726e214a96..855e9e4b97 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -30,8 +30,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Params( //64, //256, - //512, - 2048 + 512 + //1024 )] public int Count { get; set; } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats); } - //[Benchmark] + [Benchmark] public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); @@ -159,7 +159,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - //[Benchmark] + [Benchmark] public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_ConvertInSameLoop() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs index be19e719a8..ca85a350cc 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs @@ -5,6 +5,7 @@ using BenchmarkDotNet.Attributes; namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization { + [Config(typeof(Config.ShortClr))] public class UInt32ToSingle { private float[] data; @@ -66,8 +67,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization Unsafe.Add(ref bf, i) = v; } } - - // This code is not correct at all, it's just here as reference + [Benchmark] public void StandardSimdFromInt() { @@ -86,5 +86,28 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization Unsafe.Add(ref bf, i) = v; } } + + + [Benchmark] + public void StandardSimdFromInt_RefCast() + { + int n = Count / Vector.Count; + + ref Vector bf = ref Unsafe.As>(ref this.data[0]); + ref Vector bu = ref Unsafe.As, Vector>(ref bf); + + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + ref Vector fRef = ref Unsafe.Add(ref bf, i); + + Vector du = Vector.AsVectorInt32(fRef); + Vector v = Vector.ConvertToSingle(du); + v *= scale; + + fRef = v; + } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs index f71f6ec1bf..2bc3af4c98 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs @@ -3,8 +3,11 @@ using System.Runtime.CompilerServices; using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.Tuples; + namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization { + [Config(typeof(Config.ShortClr))] public class WidenBytesToUInt32 { private byte[] source; @@ -25,8 +28,8 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization { const int N = Count / 8; - ref SimdUtils.Octet.OfByte sBase = ref Unsafe.As(ref this.source[0]); - ref SimdUtils.Octet.OfUInt32 dBase = ref Unsafe.As(ref this.dest[0]); + ref Octet.OfByte sBase = ref Unsafe.As(ref this.source[0]); + ref Octet.OfUInt32 dBase = ref Unsafe.As(ref this.dest[0]); for (int i = 0; i < N; i++) { diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index 4e1717bda9..2dcba2b74b 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Tests.Common { float[] data = new float[Vector.Count]; - var rnd = new Random(); + var rnd = new Random(seed); for (int i = 0; i < Vector.Count; i++) { @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.Tests.Common [InlineData(1, 8)] [InlineData(2, 16)] [InlineData(3, 128)] - public void BulkConvertNormalizedFloatToByte_WithRoundedData(int seed, int count) + public void BasicIntrinsics_BulkConvertNormalizedFloatToByte_WithRoundedData(int seed, int count) { if (this.SkipOnNonAvx2()) { @@ -130,7 +130,7 @@ namespace SixLabors.ImageSharp.Tests.Common byte[] dest = new byte[count]; - SimdUtils.BulkConvertNormalizedFloatToByte(normalized, dest); + SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByte(normalized, dest); byte[] expected = orig.Select(f => (byte)(f)).ToArray(); @@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.Tests.Common [InlineData(1, 8)] [InlineData(2, 16)] [InlineData(3, 128)] - public void BulkConvertNormalizedFloatToByte_WithNonRoundedData(int seed, int count) + public void BasicIntrinsics_BulkConvertNormalizedFloatToByte_WithNonRoundedData(int seed, int count) { if (this.SkipOnNonAvx2()) { @@ -153,87 +153,113 @@ namespace SixLabors.ImageSharp.Tests.Common byte[] dest = new byte[count]; - SimdUtils.BulkConvertNormalizedFloatToByte(source, dest); + SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByte(source, dest); byte[] expected = source.Select(f => (byte)Math.Round(f * 255f)).ToArray(); Assert.Equal(expected, dest); } + public static readonly TheoryData ArraySizesDivisibleBy8 = new TheoryData { 0, 8, 16, 1024 }; + + public static readonly TheoryData ArraySizesDivisibleBy32 = new TheoryData { 0, 32, 512 }; + + public static readonly TheoryData ArbitraryArraySizes = + new TheoryData + { + 0, 1, 2, 3, 4, 7, 8, 9, 15, 16, 17, 63, 64, 255, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 520, + }; [Theory] - [InlineData(1, 0)] - [InlineData(2, 32)] - [InlineData(3, 128)] - public void BulkConvertByteToNormalizedFloat(int seed, int count) + [MemberData(nameof(ArraySizesDivisibleBy8))] + public void BasicIntrinsics_BulkConvertByteToNormalizedFloat(int count) { if (this.SkipOnNonAvx2()) { return; } - byte[] source = new Random(seed).GenerateRandomByteArray(count); - float[] result = new float[count]; - float[] expected = source.Select(b => (float)b / 255f).ToArray(); - - SimdUtils.BulkConvertByteToNormalizedFloat(source, result); - - Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); + TestImpl_BulkConvertByteToNormalizedFloat( + count, + (s, d) => SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(s.Span, d.Span)); } [Theory] - [InlineData(1, 0)] - [InlineData(2, 32)] - [InlineData(3, 128)] - public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat(int seed, int count) + [MemberData(nameof(ArraySizesDivisibleBy32))] + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat(int count) + { + TestImpl_BulkConvertByteToNormalizedFloat( + count, + (s, d) => SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(s.Span, d.Span)); + } + + [Theory] + [MemberData(nameof(ArbitraryArraySizes))] + public void BulkConvertByteToNormalizedFloat(int count) + { + TestImpl_BulkConvertByteToNormalizedFloat( + count, + (s, d) => SimdUtils.BulkConvertByteToNormalizedFloat(s.Span, d.Span)); + } + + private static void TestImpl_BulkConvertByteToNormalizedFloat( + int count, + Action, Memory> convert) { - byte[] source = new Random(seed).GenerateRandomByteArray(count); + byte[] source = new Random(count).GenerateRandomByteArray(count); float[] result = new float[count]; float[] expected = source.Select(b => (float)b / 255f).ToArray(); - - SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(source, result); + convert(source, result); Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); } - - public static readonly TheoryData BulkConvertNormalizedFloatToByteClampOverflows_Data = - new TheoryData - { - 0, 64, 1024 - }; - [Theory] - [MemberData(nameof(BulkConvertNormalizedFloatToByteClampOverflows_Data))] - public void BulkConvertNormalizedFloatToByteClampOverflows(int count) + [MemberData(nameof(ArraySizesDivisibleBy8))] + public void BasicIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int count) { if (this.SkipOnNonAvx2()) { return; } - float[] source = new Random(count).GenerateRandomFloatArray(count, -0.1f, 1.2f); - byte[] expected = source.Select(NormalizedFloatToByte).ToArray(); - byte[] actual = new byte[count]; - - SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(source, actual); - - Assert.Equal(expected, actual); + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, + (s, d) => SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span) + ); } [Theory] - [MemberData(nameof(BulkConvertNormalizedFloatToByteClampOverflows_Data))] + [MemberData(nameof(ArraySizesDivisibleBy32))] public void ExtendedIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int count) + { + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, + (s, d) => SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span) + ); + } + + [Theory] + [MemberData(nameof(ArbitraryArraySizes))] + public void BulkConvertNormalizedFloatToByteClampOverflows(int count) + { + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, + (s, d) => SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span) + ); + } + + private static void TestImpl_BulkConvertNormalizedFloatToByteClampOverflows( + int count, + Action, Memory> convert) { float[] source = new Random(count).GenerateRandomFloatArray(count, -0.1f, 1.2f); byte[] expected = source.Select(NormalizedFloatToByte).ToArray(); byte[] actual = new byte[count]; - SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(source, actual); + convert(source, actual); Assert.Equal(expected, actual); } + private static byte NormalizedFloatToByte(float f) => (byte)Math.Min(255f, Math.Max(0f, f * 255f + 0.5f)); [Theory] From 34ab918624f802989629402d0825a28aca82a634 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 20 Oct 2018 23:31:21 +0200 Subject: [PATCH 179/381] fix benchmarks --- .../Color/Bulk/PackFromVector4.cs | 4 +- .../Color/Bulk/ToVector4.cs | 73 ++----------------- 2 files changed, 8 insertions(+), 69 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index 1153d8f401..eb7154955e 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -95,12 +95,12 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark(Baseline = true)] - public void BulkConvertNormalizedFloatToByteClampOverflows() + public void BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); + SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); } [Benchmark] diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 855e9e4b97..c50c7ce5ad 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -30,8 +30,9 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Params( //64, //256, - 512 - //1024 + //512, + //1024, + 2048 )] public int Count { get; set; } @@ -100,12 +101,12 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark(Baseline = true)] - public void BulkConvertByteToNormalizedFloat() + public void BasicIntrinsics256_BulkConvertByteToNormalizedFloat() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - SimdUtils.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(sBytes, dFloats); } [Benchmark] @@ -117,7 +118,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats); } - [Benchmark] + //[Benchmark] public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); @@ -200,67 +201,5 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk v *= scale; return v; } - - //[Benchmark] - public void OldImplementation() - { - int count = this.Count; - var bVec = new Vector(256.0f / 255.0f); - var magicFloat = new Vector(32768.0f); - var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f - var mask = new Vector(255); - - int unpackedRawCount = count * 4; - - ref uint sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference((ReadOnlySpan)this.source.GetSpan())); - ref UnpackedRGBA destBaseAsUnpacked = ref Unsafe.As(ref MemoryMarshal.GetReference(this.destination.GetSpan())); - ref Vector destBaseAsUInt = ref Unsafe.As>(ref destBaseAsUnpacked); - ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsUnpacked); - - for (int i = 0; i < count; i++) - { - uint sVal = Unsafe.Add(ref sourceBase, i); - ref UnpackedRGBA dst = ref Unsafe.Add(ref destBaseAsUnpacked, i); - - // This call is the bottleneck now: - dst.Load(sVal); - } - - int numOfVectors = unpackedRawCount / Vector.Count; - - for (int i = 0; i < numOfVectors; i++) - { - Vector vi = Unsafe.Add(ref destBaseAsUInt, i); - - vi &= mask; - vi |= magicInt; - - var vf = Vector.AsVectorSingle(vi); - vf = (vf - magicFloat) * bVec; - - Unsafe.Add(ref destBaseAsFloat, i) = vf; - } - } - - [StructLayout(LayoutKind.Sequential)] - private struct UnpackedRGBA - { - private uint r; - - private uint g; - - private uint b; - - private uint a; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Load(uint p) - { - this.r = p; - this.g = p >> 8; - this.b = p >> 16; - this.a = p >> 24; - } - } } } \ No newline at end of file From 2fcda3cee0d4091678bf4a41bfcfa2b88a444949 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 21 Oct 2018 01:21:36 +0200 Subject: [PATCH 180/381] simplify Rgba32.PixelOperations, include benchmark results --- .../PixelFormats/PixelOperations{TPixel}.cs | 60 ++++----- .../PixelFormats/Rgba32.PixelOperations.cs | 123 ++---------------- .../Color/Bulk/PackFromVector4.cs | 41 ++++-- .../Color/Bulk/ToVector4.cs | 32 ++++- 4 files changed, 94 insertions(+), 162 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 39c442fe02..cbf164a71c 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -29,7 +29,19 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void PackFromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) { - PackFromVector4Common(sourceVectors, destinationColors, count); + ReadOnlySpan sourceVectors1 = sourceVectors; + Span destinationColors1 = destinationColors; + GuardSpans(sourceVectors1, nameof(sourceVectors1), destinationColors1, nameof(destinationColors1), count); + + ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors1); + ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors1); + + for (int i = 0; i < count; i++) + { + ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + dp.PackFromVector4(sp); + } } /// @@ -40,7 +52,19 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) { - ToVector4Common(sourceColors, destinationVectors, count); + ReadOnlySpan sourceColors1 = sourceColors; + Span destinationVectors1 = destinationVectors; + GuardSpans(sourceColors1, nameof(sourceColors1), destinationVectors1, nameof(destinationVectors1), count); + + ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors1); + ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors1); + + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref Vector4 dp = ref Unsafe.Add(ref destRef, i); + dp = sp.ToVector4(); + } } /// @@ -106,37 +130,5 @@ namespace SixLabors.ImageSharp.PixelFormats Guard.MustBeSizedAtLeast(source, minLength, sourceParamName); Guard.MustBeSizedAtLeast(destination, minLength, destinationParamName); } - - [MethodImpl(InliningOptions.ShortMethod)] - internal static void PackFromVector4Common(ReadOnlySpan sourceVectors, Span destinationColors, int count) - { - GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); - - ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); - ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); - - for (int i = 0; i < count; i++) - { - ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromVector4(sp); - } - } - - [MethodImpl(InliningOptions.ShortMethod)] - internal static void ToVector4Common(ReadOnlySpan sourceColors, Span destinationVectors, int count) - { - GuardSpans(sourceColors, nameof(sourceColors), destinationVectors, nameof(destinationVectors), count); - - ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); - ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); - - for (int i = 0; i < count; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); - ref Vector4 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToVector4(); - } - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs index 564b93ef52..bb42ec7e34 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs @@ -24,21 +24,12 @@ namespace SixLabors.ImageSharp.PixelFormats Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); Guard.MustBeSizedAtLeast(destinationVectors, count, nameof(destinationVectors)); - if (count < 128 || !SimdUtils.IsAvx2CompatibleArchitecture) - { - // Doesn't worth to bother with SIMD: - ToVector4Common(sourceColors, destinationVectors, count); - return; - } + sourceColors = sourceColors.Slice(0, count); + destinationVectors = destinationVectors.Slice(0, count); - if (SimdUtils.ExtendedIntrinsics.IsAvailable) - { - ConvertToVector4UsingExtendedIntrinsics(sourceColors, destinationVectors, count); - } - else - { - ConvertToVector4UsingBasicIntrinsics(sourceColors, destinationVectors, count); - } + SimdUtils.BulkConvertByteToNormalizedFloat( + MemoryMarshal.Cast(sourceColors), + MemoryMarshal.Cast(destinationVectors)); } /// @@ -46,20 +37,12 @@ namespace SixLabors.ImageSharp.PixelFormats { GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); - if (count < 128 || !SimdUtils.IsAvx2CompatibleArchitecture) - { - PackFromVector4Common(sourceVectors, destinationColors, count); - return; - } + sourceVectors = sourceVectors.Slice(0, count); + destinationColors = destinationColors.Slice(0, count); - if (SimdUtils.ExtendedIntrinsics.IsAvailable) - { - ConvertFromVector4ExtendedIntrinsics(sourceVectors, destinationColors, count); - } - else - { - ConvertFromVector4BasicIntrinsics(sourceVectors, destinationColors, count); - } + SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( + MemoryMarshal.Cast(sourceVectors), + MemoryMarshal.Cast(destinationColors)); } /// @@ -89,92 +72,6 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(dest); } - - private static void ConvertToVector4UsingExtendedIntrinsics( - ReadOnlySpan sourceColors, - Span destinationVectors, - int count) - { - int remainder = count % 8; - int alignedCount = count - remainder; - - if (alignedCount > 0) - { - ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceColors); - Span rawDest = MemoryMarshal.Cast(destinationVectors.Slice(0, alignedCount)); - - SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(rawSrc, rawDest); - } - - if (remainder > 0) - { - ToVector4Common(sourceColors.Slice(alignedCount), destinationVectors.Slice(alignedCount), remainder); - } - } - - private static void ConvertToVector4UsingBasicIntrinsics( - ReadOnlySpan sourceColors, - Span destinationVectors, - int count) - { - int remainder = count % 2; - int alignedCount = count - remainder; - - if (alignedCount > 0) - { - ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceColors); - Span rawDest = MemoryMarshal.Cast(destinationVectors.Slice(0, alignedCount)); - - SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(rawSrc, rawDest); - } - - if (remainder > 0) - { - // actually: remainder == 1 - int lastIdx = count - 1; - destinationVectors[lastIdx] = sourceColors[lastIdx].ToVector4(); - } - } - - private static void ConvertFromVector4ExtendedIntrinsics(ReadOnlySpan sourceVectors, Span destinationColors, int count) - { - int remainder = count % 8; - int alignedCount = count - remainder; - - if (alignedCount > 0) - { - ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceVectors); - Span rawDest = MemoryMarshal.Cast(destinationColors.Slice(0, alignedCount)); - - SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(rawSrc, rawDest); - } - - if (remainder > 0) - { - PackFromVector4Common(sourceVectors.Slice(alignedCount), destinationColors.Slice(alignedCount), remainder); - } - } - - private static void ConvertFromVector4BasicIntrinsics(ReadOnlySpan sourceVectors, Span destinationColors, int count) - { - int remainder = count % 2; - int alignedCount = count - remainder; - - if (alignedCount > 0) - { - ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceVectors.Slice(0, alignedCount)); - Span rawDest = MemoryMarshal.Cast(destinationColors); - - SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflows(rawSrc, rawDest); - } - - if (remainder > 0) - { - // actually: remainder == 1 - int lastIdx = count - 1; - destinationColors[lastIdx].PackFromVector4(sourceVectors[lastIdx]); - } - } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index eb7154955e..7a212b0523 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk protected IMemoryOwner destination; [Params( - //64, + 64, 2048 )] public int Count { get; set; } @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk public class PackFromVector4_Rgba32 : PackFromVector4 { [Benchmark] - public void FastDefault() + public void BasicBulk() { ref Vector4 sBase = ref this.source.GetSpan()[0]; ref Rgba32 dBase = ref this.destination.GetSpan()[0]; @@ -112,16 +112,31 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); } - // RESULTS: - // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Allocated | - // ----------------------------------------------------------------- |-------- |------ |----------:|----------:|----------:|-------:|---------:|----------:| - // FastDefault | Clr | 2048 | 15.989 us | 6.1384 us | 0.3468 us | 4.07 | 0.08 | 0 B | - // BulkConvertNormalizedFloatToByteClampOverflows | Clr | 2048 | 3.931 us | 0.6264 us | 0.0354 us | 1.00 | 0.00 | 0 B | - // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 2048 | 2.100 us | 0.4717 us | 0.0267 us | 0.53 | 0.01 | 0 B | - // - // | | | | | | | | | - // FastDefault | Core | 2048 | 14.693 us | 0.5131 us | 0.0290 us | 3.76 | 0.03 | 0 B | - // BulkConvertNormalizedFloatToByteClampOverflows | Core | 2048 | 3.913 us | 0.5661 us | 0.0320 us | 1.00 | 0.00 | 0 B | - // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Core | 2048 | 1.966 us | 0.4056 us | 0.0229 us | 0.50 | 0.01 | 0 B | + // RESULTS (2018 October): + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ------------------------------------------------------------------ |-------- |------ |-------------:|-------------:|-----------:|-------:|---------:|-------:|----------:| + // BasicBulk | Clr | 64 | 581.62 ns | 33.625 ns | 1.8999 ns | 2.27 | 0.02 | - | 0 B | + // BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 64 | 256.66 ns | 45.153 ns | 2.5512 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 64 | 201.92 ns | 30.161 ns | 1.7042 ns | 0.79 | 0.01 | - | 0 B | + // PixelOperations_Base | Clr | 64 | 665.01 ns | 13.032 ns | 0.7363 ns | 2.59 | 0.02 | 0.0067 | 24 B | + // PixelOperations_Specialized | Clr | 64 | 295.14 ns | 26.335 ns | 1.4880 ns | 1.15 | 0.01 | - | 0 B | + // | | | | | | | | | | + // BasicBulk | Core | 64 | 513.22 ns | 91.110 ns | 5.1479 ns | 3.19 | 0.03 | - | 0 B | + // BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows | Core | 64 | 160.76 ns | 2.760 ns | 0.1559 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Core | 64 | 95.98 ns | 10.077 ns | 0.5694 ns | 0.60 | 0.00 | - | 0 B | + // PixelOperations_Base | Core | 64 | 591.74 ns | 49.856 ns | 2.8170 ns | 3.68 | 0.01 | 0.0067 | 24 B | + // PixelOperations_Specialized | Core | 64 | 149.11 ns | 4.485 ns | 0.2534 ns | 0.93 | 0.00 | - | 0 B | + // | | | | | | | | | | + // BasicBulk | Clr | 2048 | 15,345.85 ns | 1,213.551 ns | 68.5679 ns | 3.90 | 0.01 | - | 0 B | + // BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 2048 | 3,939.49 ns | 71.101 ns | 4.0173 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 2048 | 2,272.61 ns | 110.671 ns | 6.2531 ns | 0.58 | 0.00 | - | 0 B | + // PixelOperations_Base | Clr | 2048 | 17,422.47 ns | 811.733 ns | 45.8644 ns | 4.42 | 0.01 | - | 24 B | + // PixelOperations_Specialized | Clr | 2048 | 3,984.26 ns | 110.352 ns | 6.2351 ns | 1.01 | 0.00 | - | 0 B | + // | | | | | | | | | | + // BasicBulk | Core | 2048 | 14,950.43 ns | 699.309 ns | 39.5123 ns | 3.76 | 0.02 | - | 0 B | + // BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows | Core | 2048 | 3,978.28 ns | 481.105 ns | 27.1833 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Core | 2048 | 2,169.54 ns | 75.606 ns | 4.2719 ns | !!0.55!| 0.00 | - | 0 B | + // PixelOperations_Base | Core | 2048 | 18,403.62 ns | 1,494.056 ns | 84.4169 ns | 4.63 | 0.03 | - | 24 B | + // PixelOperations_Specialized | Core | 2048 | 2,227.60 ns | 486.761 ns | 27.5029 ns | !!0.56!| 0.01 | - | 0 B | } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index c50c7ce5ad..4a801d64ef 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk protected IMemoryOwner destination; [Params( - //64, + 64, //256, //512, //1024, @@ -160,7 +160,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - [Benchmark] + //[Benchmark] public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_ConvertInSameLoop() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); @@ -201,5 +201,33 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk v *= scale; return v; } + + // RESULTS (2018 October): + // + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ---------------------------------------------------- |-------- |------ |------------:|-------------:|-----------:|-------:|---------:|-------:|----------:| + // BasicBulk | Clr | 64 | 267.40 ns | 30.711 ns | 1.7352 ns | 1.07 | 0.01 | - | 0 B | + // BasicIntrinsics256_BulkConvertByteToNormalizedFloat | Clr | 64 | 249.97 ns | 33.838 ns | 1.9119 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics_BulkConvertByteToNormalizedFloat | Clr | 64 | 176.97 ns | 5.221 ns | 0.2950 ns | 0.71 | 0.00 | - | 0 B | + // PixelOperations_Base | Clr | 64 | 349.70 ns | 104.331 ns | 5.8949 ns | 1.40 | 0.02 | 0.0072 | 24 B | + // PixelOperations_Specialized | Clr | 64 | 288.31 ns | 26.833 ns | 1.5161 ns | 1.15 | 0.01 | - | 0 B | + // | | | | | | | | | | + // BasicBulk | Core | 64 | 185.36 ns | 30.051 ns | 1.6979 ns | 1.26 | 0.01 | - | 0 B | + // BasicIntrinsics256_BulkConvertByteToNormalizedFloat | Core | 64 | 146.84 ns | 12.674 ns | 0.7161 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics_BulkConvertByteToNormalizedFloat | Core | 64 | 67.31 ns | 2.542 ns | 0.1436 ns | 0.46 | 0.00 | - | 0 B | + // PixelOperations_Base | Core | 64 | 272.03 ns | 94.419 ns | 5.3348 ns | 1.85 | 0.03 | 0.0072 | 24 B | + // PixelOperations_Specialized | Core | 64 | 121.91 ns | 31.477 ns | 1.7785 ns | 0.83 | 0.01 | - | 0 B | + // | | | | | | | | | | + // BasicBulk | Clr | 2048 | 5,133.04 ns | 284.052 ns | 16.0494 ns | 1.21 | 0.01 | - | 0 B | + // BasicIntrinsics256_BulkConvertByteToNormalizedFloat | Clr | 2048 | 4,248.58 ns | 1,095.887 ns | 61.9196 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics_BulkConvertByteToNormalizedFloat | Clr | 2048 | 1,214.02 ns | 184.349 ns | 10.4160 ns | 0.29 | 0.00 | - | 0 B | + // PixelOperations_Base | Clr | 2048 | 7,096.04 ns | 362.350 ns | 20.4734 ns | 1.67 | 0.02 | - | 24 B | + // PixelOperations_Specialized | Clr | 2048 | 4,314.19 ns | 204.964 ns | 11.5809 ns | 1.02 | 0.01 | - | 0 B | + // | | | | | | | | | | + // BasicBulk | Core | 2048 | 5,038.38 ns | 223.282 ns | 12.6158 ns | 1.20 | 0.01 | - | 0 B | + // BasicIntrinsics256_BulkConvertByteToNormalizedFloat | Core | 2048 | 4,199.17 ns | 897.985 ns | 50.7378 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics_BulkConvertByteToNormalizedFloat | Core | 2048 | 1,113.86 ns | 64.799 ns | 3.6613 ns | !!0.27!| 0.00 | - | 0 B | + // PixelOperations_Base | Core | 2048 | 7,015.00 ns | 920.083 ns | 51.9864 ns | 1.67 | 0.02 | - | 24 B | + // PixelOperations_Specialized | Core | 2048 | 1,176.59 ns | 256.955 ns | 14.5184 ns | !!0.28!| 0.00 | - | 0 B | } } \ No newline at end of file From cb8b48dcbaf0e4fc3f5d7402b7b488f1c9a0ce3d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 21 Oct 2018 01:31:55 +0200 Subject: [PATCH 181/381] cleanup code and comments --- .../Helpers/SimdUtils.BasicIntrinsics256.cs | 96 +++++++++---------- .../Helpers/SimdUtils.ExtendedIntrinsics.cs | 10 +- src/ImageSharp/Common/Helpers/SimdUtils.cs | 28 +++--- 3 files changed, 67 insertions(+), 67 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs index e4dc1a1d8f..a8b3434980 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs @@ -46,53 +46,6 @@ namespace SixLabors.ImageSharp } } - /// - /// Convert 'source.Length' values normalized into [0..1] from 'source' - /// into 'dest' buffer of . The values are scaled up into [0-255] and rounded. - /// The implementation is SIMD optimized and works only with `source.Length` divisible by 8/>. - /// Based on: - /// - /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions - /// - /// - internal static void BulkConvertNormalizedFloatToByte(ReadOnlySpan source, Span dest) - { - GuardAvx2(nameof(BulkConvertNormalizedFloatToByte)); - - DebugGuard.IsTrue((source.Length % Vector.Count) == 0, nameof(source), "source.Length should be divisable by Vector.Count!"); - - if (source.Length == 0) - { - return; - } - - ref Vector srcBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - ref Octet.OfByte destBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - int n = source.Length / 8; - - Vector magick = new Vector(32768.0f); - Vector scale = new Vector(255f) / new Vector(256f); - - // need to copy to a temporary struct, because - // SimdUtils.Octet.OfUInt32 temp = Unsafe.As, SimdUtils.Octet.OfUInt32>(ref x) - // does not work. TODO: This might be a CoreClr bug, need to ask/report - var temp = default(Octet.OfUInt32); - ref Vector tempRef = ref Unsafe.As>(ref temp); - - for (int i = 0; i < n; i++) - { - // union { float f; uint32_t i; } u; - // u.f = 32768.0f + x * (255.0f / 256.0f); - // return (uint8_t)u.i; - Vector x = Unsafe.Add(ref srcBase, i); - x = (x * scale) + magick; - tempRef = x; - - ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i); - d.LoadFrom(ref temp); - } - } - /// /// SIMD optimized implementation for . /// Works only with `dest.Length` divisible by 8. @@ -165,7 +118,7 @@ namespace SixLabors.ImageSharp } /// - /// Same as but clamps overflown values before conversion. + /// Implementation of which is faster on older runtimes. /// internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) { @@ -207,6 +160,53 @@ namespace SixLabors.ImageSharp d.LoadFrom(ref temp); } } + + /// + /// Convert 'source.Length' values normalized into [0..1] from 'source' + /// into 'dest' buffer of . The values are scaled up into [0-255] and rounded. + /// The implementation is SIMD optimized and works only with `source.Length` divisible by 8. + /// Based on: + /// + /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions + /// + /// + internal static void BulkConvertNormalizedFloatToByte(ReadOnlySpan source, Span dest) + { + GuardAvx2(nameof(BulkConvertNormalizedFloatToByte)); + + DebugGuard.IsTrue((source.Length % Vector.Count) == 0, nameof(source), "source.Length should be divisable by Vector.Count!"); + + if (source.Length == 0) + { + return; + } + + ref Vector srcBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Octet.OfByte destBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + int n = source.Length / 8; + + Vector magick = new Vector(32768.0f); + Vector scale = new Vector(255f) / new Vector(256f); + + // need to copy to a temporary struct, because + // SimdUtils.Octet.OfUInt32 temp = Unsafe.As, SimdUtils.Octet.OfUInt32>(ref x) + // does not work. TODO: This might be a CoreClr bug, need to ask/report + var temp = default(Octet.OfUInt32); + ref Vector tempRef = ref Unsafe.As>(ref temp); + + for (int i = 0; i < n; i++) + { + // union { float f; uint32_t i; } u; + // u.f = 32768.0f + x * (255.0f / 256.0f); + // return (uint8_t)u.i; + Vector x = Unsafe.Add(ref srcBase, i); + x = (x * scale) + magick; + tempRef = x; + + ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i); + d.LoadFrom(ref temp); + } + } } } } \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index 5c0b8ee93a..fd263b54c5 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -52,9 +52,8 @@ namespace SixLabors.ImageSharp } /// - /// A variant of , which is faster on new RyuJIT runtime. + /// Implementation , which is faster on new RyuJIT runtime. /// - // ReSharper disable once MemberHidesStaticFromOuterClass internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { DebugGuard.IsTrue( @@ -116,13 +115,8 @@ namespace SixLabors.ImageSharp } /// - /// A variant of , which is faster on new .NET runtime. + /// Implementation of , which is faster on new .NET runtime. /// - /// - /// It does NOT worth yet to utilize this method (2018 Oct). - /// See benchmark results for the "PackFromVector4_Rgba32" benchmark! - /// TODO: Check again later! - /// internal static void BulkConvertNormalizedFloatToByteClampOverflows( ReadOnlySpan source, Span dest) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index 73e9bacfa8..111ac22408 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -22,17 +22,10 @@ namespace SixLabors.ImageSharp public static bool IsAvx2CompatibleArchitecture { get; } = Vector.IsHardwareAccelerated && Vector.Count == 8 && Vector.Count == 8; - internal static void GuardAvx2(string operation) - { - if (!IsAvx2CompatibleArchitecture) - { - throw new NotSupportedException($"{operation} is supported only on AVX2 CPU!"); - } - } - /// /// Transform all scalars in 'v' in a way that converting them to would have rounding semantics. /// + /// The vector [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static Vector4 PseudoRound(this Vector4 v) { @@ -48,14 +41,15 @@ namespace SixLabors.ImageSharp /// https://github.com/g-truc/glm/blob/master/glm/simd/common.h#L110 /// /// + /// The vector [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector FastRound(this Vector x) + internal static Vector FastRound(this Vector v) { Vector magic0 = new Vector(int.MinValue); // 0x80000000 Vector sgn0 = Vector.AsVectorSingle(magic0); - Vector and0 = Vector.BitwiseAnd(sgn0, x); + Vector and0 = Vector.BitwiseAnd(sgn0, v); Vector or0 = Vector.BitwiseOr(and0, new Vector(8388608.0f)); - Vector add0 = Vector.Add(x, or0); + Vector add0 = Vector.Add(v, or0); Vector sub0 = Vector.Subtract(add0, or0); return sub0; } @@ -65,6 +59,8 @@ namespace SixLabors.ImageSharp /// should be the of the same size as , /// but there are no restrictions on the span's length. /// + /// The source span of bytes + /// The destination span of floats internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); @@ -92,6 +88,8 @@ namespace SixLabors.ImageSharp /// should be the of the same size as , /// but there are no restrictions on the span's length. /// + /// The source span of floats + /// The destination span of bytes internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); @@ -119,5 +117,13 @@ namespace SixLabors.ImageSharp } } } + + private static void GuardAvx2(string operation) + { + if (!IsAvx2CompatibleArchitecture) + { + throw new NotSupportedException($"{operation} is supported only on AVX2 CPU!"); + } + } } } \ No newline at end of file From d1d52a713336fd3e411777044cdbd474c245a3b8 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 21 Oct 2018 17:29:34 +0200 Subject: [PATCH 182/381] FallbackIntrinsics128 + ImageMaths.Modulo* implementations --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 16 ++ .../Helpers/SimdUtils.BasicIntrinsics256.cs | 2 +- .../Helpers/SimdUtils.ExtendedIntrinsics.cs | 5 +- .../SimdUtils.FallbackIntrinsics128.cs | 143 ++++++++++++++++++ src/ImageSharp/Common/Helpers/SimdUtils.cs | 6 +- .../Color/Bulk/PackFromVector4.cs | 26 +--- .../Color/Bulk/ToVector4.cs | 25 +-- .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 27 +++- .../Helpers/ImageMathsTests.cs | 54 +++++++ 9 files changed, 256 insertions(+), 48 deletions(-) create mode 100644 src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 35769d96a7..e4fd9bce60 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -39,6 +39,22 @@ namespace SixLabors.ImageSharp return (a / GreatestCommonDivisor(a, b)) * b; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int Modulo4(int a) => a & 3; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int Modulo8(int a) => a & 7; + + /// + /// Fast (mod m) calculator, + /// where should be a power of 2. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ModuloP2(int a, int m) + { + return a & (m - 1); + } + /// /// Returns the absolute value of a 32-bit signed integer. Uses bit shifting to speed up the operation. /// diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs index a8b3434980..c7fd21a8f0 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp internal static partial class SimdUtils { /// - /// 256bit / AVX2 intrinsics NOT depending on newer API-s (Vector.Widen, Vector.Narrow, Vector.ConvertTo*) + /// Implementation with 256bit / AVX2 intrinsics NOT depending on newer API-s (Vector.Widen etc.) /// public static class BasicIntrinsics256 { diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index fd263b54c5..996a08fb4b 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -10,8 +10,9 @@ namespace SixLabors.ImageSharp internal static partial class SimdUtils { /// - /// Methods accelerated only in RyuJIT having dotnet/coreclr#10662 merged (.NET Core 2.1+ .NET 4.7.2+) - /// PR: + /// Implementation methods based on newer API-s (Vector.Widen, Vector.Narrow, Vector.ConvertTo*). + /// Only accelerated only on RyuJIT having dotnet/coreclr#10662 merged (.NET Core 2.1+ .NET 4.7.2+) + /// See: /// https://github.com/dotnet/coreclr/pull/10662 /// API Proposal: /// https://github.com/dotnet/corefx/issues/15957 diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs new file mode 100644 index 0000000000..bb21474660 --- /dev/null +++ b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs @@ -0,0 +1,143 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp +{ + internal static partial class SimdUtils + { + /// + /// Fallback implementation based on (128bit). + /// For , efficient software fallback implementations are present + /// + maybe even mono can emit intrinsics for that type :P + /// + public static class FallbackIntrinsics128 + { + /// + /// as much elements as possible, slicing them down (keeping the remainder). + /// + internal static void BulkConvertByteToNormalizedFloatReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + + int remainder = source.Length % 4; + int alignedCount = source.Length - remainder; + + if (alignedCount > 0) + { + BulkConvertByteToNormalizedFloat( + source.Slice(0, alignedCount), + dest.Slice(0, alignedCount)); + + source = source.Slice(alignedCount); + dest = dest.Slice(alignedCount); + } + } + + /// + /// as much elements as possible, slicing them down (keeping the remainder). + /// + internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + + int remainder = source.Length % 4; + int alignedCount = source.Length - remainder; + + if (alignedCount > 0) + { + BulkConvertNormalizedFloatToByteClampOverflows( + source.Slice(0, alignedCount), + dest.Slice(0, alignedCount)); + + source = source.Slice(alignedCount); + dest = dest.Slice(alignedCount); + } + } + + /// + /// Implementation of using . + /// + internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + { + DebugGuard.IsTrue((dest.Length % 4) == 0, nameof(dest), "dest.Length should be divisible by 4!"); + + int count = dest.Length / 4; + if (count == 0) + { + return; + } + + ref ByteVector4 sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref Vector4 dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + + const float Scale = 1f / 255f; + Vector4 d = default; + + for (int i = 0; i < count; i++) + { + ref ByteVector4 s = ref Unsafe.Add(ref sBase, i); + d.X = s.X; + d.Y = s.Y; + d.Z = s.Z; + d.W = s.W; + d *= Scale; + Unsafe.Add(ref dBase, i) = d; + } + } + + /// + /// Implementation of using . + /// + internal static void BulkConvertNormalizedFloatToByteClampOverflows( + ReadOnlySpan source, + Span dest) + { + DebugGuard.IsTrue((source.Length % 4) == 0, nameof(source), "source.Length should be divisible by 4!"); + + int count = source.Length / 4; + if (count == 0) + { + return; + } + + ref Vector4 sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref ByteVector4 dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + + var half = new Vector4(0.5f); + var maxBytes = new Vector4(255f); + + for (int i = 0; i < count; i++) + { + Vector4 s = Unsafe.Add(ref sBase, i); + s *= maxBytes; + s += half; + + // I'm not sure if Clamp() is properly implemented with intrinsics. + s = Vector4.Max(Vector4.Zero, s); + s = Vector4.Min(maxBytes, s); + + ref ByteVector4 d = ref Unsafe.Add(ref dBase, i); + d.X = (byte)s.X; + d.Y = (byte)s.Y; + d.Z = (byte)s.Z; + d.W = (byte)s.W; + } + } + + [StructLayout(LayoutKind.Sequential)] + private struct ByteVector4 + { + public byte X; + public byte Y; + public byte Z; + public byte W; + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index 111ac22408..bc75dc8caa 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp } /// - /// Converts `dest.Length` -s to -s normalized into [0..1]. + /// Converts all input -s to -s normalized into [0..1]. /// should be the of the same size as , /// but there are no restrictions on the span's length. /// @@ -67,6 +67,7 @@ namespace SixLabors.ImageSharp ExtendedIntrinsics.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); BasicIntrinsics256.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); + FallbackIntrinsics128.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); // Deal with the remainder: int count = source.Length; @@ -83,7 +84,7 @@ namespace SixLabors.ImageSharp } /// - /// Convert 'source.Length' values normalized into [0..1] from 'source' into 'dest' buffer of . + /// Convert all values normalized into [0..1] from 'source' into 'dest' buffer of . /// The values are scaled up into [0-255] and rounded, overflows are clamped. /// should be the of the same size as , /// but there are no restrictions on the span's length. @@ -96,6 +97,7 @@ namespace SixLabors.ImageSharp ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); + FallbackIntrinsics128.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); // Deal with the remainder: int count = source.Length; diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index 7a212b0523..a56082fcd3 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -72,30 +72,16 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk public class PackFromVector4_Rgba32 : PackFromVector4 { [Benchmark] - public void BasicBulk() + public void FallbackIntrinsics128() { - ref Vector4 sBase = ref this.source.GetSpan()[0]; - ref Rgba32 dBase = ref this.destination.GetSpan()[0]; - - Vector4 maxBytes = new Vector4(255); - Vector4 half = new Vector4(0.5f); + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - for (int i = 0; i < this.Count; i++) - { - Vector4 v = Unsafe.Add(ref sBase, i); - v *= maxBytes; - v += half; - v = Vector4.Clamp(v, Vector4.Zero, maxBytes); - ref Rgba32 d = ref Unsafe.Add(ref dBase, i); - d.R = (byte)v.X; - d.G = (byte)v.Y; - d.B = (byte)v.Z; - d.A = (byte)v.W; - } + SimdUtils.FallbackIntrinsics128.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); } [Benchmark(Baseline = true)] - public void BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows() + public void BasicIntrinsics256() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); @@ -104,7 +90,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark] - public void ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows() + public void ExtendedIntrinsic() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 4a801d64ef..519edaa31f 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -79,29 +79,16 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk public class ToVector4_Rgba32 : ToVector4 { [Benchmark] - public void BasicBulk() + public void FallbackIntrinsics128() { - ref Rgba32 sBase = ref this.source.GetSpan()[0]; - ref Vector4 dBase = ref this.destination.GetSpan()[0]; - - Vector4 scale = new Vector4(1f / 255f); - - Vector4 v = default; + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - for (int i = 0; i < this.Count; i++) - { - ref Rgba32 s = ref Unsafe.Add(ref sBase, i); - v.X = s.R; - v.Y = s.G; - v.Z = s.B; - v.W = s.A; - v *= scale; - Unsafe.Add(ref dBase, i) = v; - } + SimdUtils.FallbackIntrinsics128.BulkConvertByteToNormalizedFloat(sBytes, dFloats); } [Benchmark(Baseline = true)] - public void BasicIntrinsics256_BulkConvertByteToNormalizedFloat() + public void BasicIntrinsics256() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); @@ -110,7 +97,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark] - public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat() + public void ExtendedIntrinsics() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index 2dcba2b74b..feefd17580 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.Tests.Common [InlineData(1, 8)] [InlineData(2, 16)] [InlineData(3, 128)] - public void BasicIntrinsics_BulkConvertNormalizedFloatToByte_WithRoundedData(int seed, int count) + public void BasicIntrinsics256_BulkConvertNormalizedFloatToByte_WithRoundedData(int seed, int count) { if (this.SkipOnNonAvx2()) { @@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.Tests.Common [InlineData(1, 8)] [InlineData(2, 16)] [InlineData(3, 128)] - public void BasicIntrinsics_BulkConvertNormalizedFloatToByte_WithNonRoundedData(int seed, int count) + public void BasicIntrinsics256_BulkConvertNormalizedFloatToByte_WithNonRoundedData(int seed, int count) { if (this.SkipOnNonAvx2()) { @@ -161,6 +161,7 @@ namespace SixLabors.ImageSharp.Tests.Common } public static readonly TheoryData ArraySizesDivisibleBy8 = new TheoryData { 0, 8, 16, 1024 }; + public static readonly TheoryData ArraySizesDivisibleBy4 = new TheoryData { 0, 4, 8, 28, 1020 }; public static readonly TheoryData ArraySizesDivisibleBy32 = new TheoryData { 0, 32, 512 }; @@ -170,9 +171,18 @@ namespace SixLabors.ImageSharp.Tests.Common 0, 1, 2, 3, 4, 7, 8, 9, 15, 16, 17, 63, 64, 255, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 520, }; + [Theory] + [MemberData(nameof(ArraySizesDivisibleBy4))] + public void FallbackIntrinsics128_BulkConvertByteToNormalizedFloat(int count) + { + TestImpl_BulkConvertByteToNormalizedFloat( + count, + (s, d) => SimdUtils.FallbackIntrinsics128.BulkConvertByteToNormalizedFloat(s.Span, d.Span)); + } + [Theory] [MemberData(nameof(ArraySizesDivisibleBy8))] - public void BasicIntrinsics_BulkConvertByteToNormalizedFloat(int count) + public void BasicIntrinsics256_BulkConvertByteToNormalizedFloat(int count) { if (this.SkipOnNonAvx2()) { @@ -215,9 +225,18 @@ namespace SixLabors.ImageSharp.Tests.Common Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); } + [Theory] + [MemberData(nameof(ArraySizesDivisibleBy4))] + public void FallbackIntrinsics128_BulkConvertNormalizedFloatToByteClampOverflows(int count) + { + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, + (s, d) => SimdUtils.FallbackIntrinsics128.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span) + ); + } + [Theory] [MemberData(nameof(ArraySizesDivisibleBy8))] - public void BasicIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int count) + public void BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows(int count) { if (this.SkipOnNonAvx2()) { diff --git a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs index 6c2979fe9e..aec4d0b810 100644 --- a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs @@ -9,6 +9,60 @@ namespace SixLabors.ImageSharp.Tests.Helpers public class ImageMathsTests { + [Theory] + [InlineData(0, 0)] + [InlineData(1, 1)] + [InlineData(2, 2)] + [InlineData(3, 3)] + [InlineData(4, 0)] + [InlineData(100, 0)] + [InlineData(123, 3)] + [InlineData(53436353, 1)] + public void Modulo4(int a, int expected) + { + int actual = ImageMaths.Modulo4(a); + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(0, 0)] + [InlineData(1, 1)] + [InlineData(2, 2)] + [InlineData(6, 6)] + [InlineData(7, 7)] + [InlineData(8, 0)] + [InlineData(100, 4)] + [InlineData(123, 3)] + [InlineData(53436353, 1)] + [InlineData(975, 7)] + public void Modulo8(int a, int expected) + { + int actual = ImageMaths.Modulo8(a); + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(0, 2, 0)] + [InlineData(1, 2, 1)] + [InlineData(2, 2, 0)] + [InlineData(0, 4, 0)] + [InlineData(3, 4, 3)] + [InlineData(5, 4, 1)] + [InlineData(5, 8, 5)] + [InlineData(8, 8, 0)] + [InlineData(8, 16, 8)] + [InlineData(15, 16, 15)] + [InlineData(17, 16, 1)] + [InlineData(17, 32, 17)] + [InlineData(31, 32, 31)] + [InlineData(32, 32, 0)] + [InlineData(33, 32, 1)] + public void Modulo2P(int a, int m, int expected) + { + int actual = ImageMaths.ModuloP2(a, m); + Assert.Equal(expected, actual); + } + [Fact] public void FasAbsResultMatchesMath() { From bf7c9338960aa5d6846d6062c107e2305c518609 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 21 Oct 2018 21:00:15 +0200 Subject: [PATCH 183/381] minimize ceremonial overhead in BulkConvertByteToNormalizedFloat() and BulkConvertNormalizedFloatToByteClampOverflows() --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 45 +++++---- .../Helpers/SimdUtils.BasicIntrinsics256.cs | 91 ++++++++++-------- .../Helpers/SimdUtils.ExtendedIntrinsics.cs | 96 ++++++++++--------- .../SimdUtils.FallbackIntrinsics128.cs | 56 +++++++---- src/ImageSharp/Common/Helpers/SimdUtils.cs | 84 +++++++++++----- .../Color/Bulk/PackFromVector4.cs | 50 +++++----- .../Color/Bulk/ToVector4.cs | 50 +++++----- .../General/{ => BasicMath}/Abs.cs | 8 +- .../General/{ => BasicMath}/Clamp.cs | 10 +- .../BasicMath/ModuloPowerOfTwoConstant.cs | 23 +++++ .../BasicMath/ModuloPowerOfTwoVariable.cs | 32 +++++++ .../General/{ => BasicMath}/Pow.cs | 3 +- .../ImageSharp.Benchmarks/General/Modulus.cs | 19 ---- .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 17 +++- .../Helpers/ImageMathsTests.cs | 94 ++++++++++-------- 15 files changed, 406 insertions(+), 272 deletions(-) rename tests/ImageSharp.Benchmarks/General/{ => BasicMath}/Abs.cs (88%) rename tests/ImageSharp.Benchmarks/General/{ => BasicMath}/Clamp.cs (94%) create mode 100644 tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoConstant.cs create mode 100644 tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoVariable.cs rename tests/ImageSharp.Benchmarks/General/{ => BasicMath}/Pow.cs (93%) delete mode 100644 tests/ImageSharp.Benchmarks/General/Modulus.cs diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index e4fd9bce60..1395975ec8 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -39,22 +39,31 @@ namespace SixLabors.ImageSharp return (a / GreatestCommonDivisor(a, b)) * b; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int Modulo4(int a) => a & 3; + /// + /// Calculates % 4 + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static int Modulo4(int x) => x & 3; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int Modulo8(int a) => a & 7; + /// + /// Calculates % 8 + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static int Modulo8(int x) => x & 7; /// - /// Fast (mod m) calculator, - /// where should be a power of 2. + /// Fast (x mod m) calculator, with the restriction that + /// should be power of 2. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ModuloP2(int a, int m) + [MethodImpl(InliningOptions.ShortMethod)] + public static int ModuloP2(int x, int m) { - return a & (m - 1); + return x & (m - 1); } + [MethodImpl(InliningOptions.ShortMethod)] + public static float Clamp(float x, float min, float max) => Math.Min(max, Math.Max(min, x)); + /// /// Returns the absolute value of a 32-bit signed integer. Uses bit shifting to speed up the operation. /// @@ -62,7 +71,7 @@ namespace SixLabors.ImageSharp /// A number that is greater than , but less than or equal to /// /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static int FastAbs(int x) { int y = x >> 31; @@ -74,7 +83,7 @@ namespace SixLabors.ImageSharp /// /// A single-precision floating-point number /// The number raised to the power of 2. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float Pow2(float x) => x * x; /// @@ -82,7 +91,7 @@ namespace SixLabors.ImageSharp /// /// A single-precision floating-point number /// The number raised to the power of 3. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float Pow3(float x) => x * x * x; /// @@ -93,7 +102,7 @@ namespace SixLabors.ImageSharp /// /// The /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static int GetBitsNeededForColorDepth(int colors) => Math.Max(1, (int)Math.Ceiling(Math.Log(colors, 2))); /// @@ -101,7 +110,7 @@ namespace SixLabors.ImageSharp /// /// The bit depth. /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static int GetColorCountForBitDepth(int bitDepth) => 1 << bitDepth; /// @@ -110,7 +119,7 @@ namespace SixLabors.ImageSharp /// The x provided to G(x). /// The spread of the blur. /// The Gaussian G(x) - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float Gaussian(float x, float sigma) { const float Numerator = 1.0f; @@ -133,7 +142,7 @@ namespace SixLabors.ImageSharp /// /// The sine cardinal of . /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float SinC(float f) { if (MathF.Abs(f) > Constants.Epsilon) @@ -156,7 +165,7 @@ namespace SixLabors.ImageSharp /// /// The . /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float GetBcValue(float x, float b, float c) { if (x < 0F) @@ -192,7 +201,7 @@ namespace SixLabors.ImageSharp /// /// The bounding . /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static Rectangle GetBoundingRectangle(Point topLeft, Point bottomRight) => new Rectangle(topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y); /// diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs index c7fd21a8f0..713d606e79 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs @@ -21,28 +21,58 @@ namespace SixLabors.ImageSharp public static bool IsAvailable { get; } = IsAvx2CompatibleArchitecture; /// - /// as much elements as possible, slicing them down (keeping the remainder). + /// as many elements as possible, slicing them down (keeping the remainder). /// + [MethodImpl(InliningOptions.ShortMethod)] internal static void BulkConvertByteToNormalizedFloatReduce( ref ReadOnlySpan source, ref Span dest) { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); - if (IsAvailable) + if (!IsAvailable) { - int remainder = source.Length % 8; - int alignedCount = source.Length - remainder; - - if (alignedCount > 0) - { - BulkConvertByteToNormalizedFloat( - source.Slice(0, alignedCount), - dest.Slice(0, alignedCount)); - - source = source.Slice(alignedCount); - dest = dest.Slice(alignedCount); - } + return; + } + + int remainder = ImageMaths.Modulo8(source.Length); + int adjustedCount = source.Length - remainder; + + if (adjustedCount > 0) + { + BulkConvertByteToNormalizedFloat( + source.Slice(0, adjustedCount), + dest.Slice(0, adjustedCount)); + + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); + } + } + + /// + /// as many elements as possible, slicing them down (keeping the remainder). + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + + if (!IsAvailable) + { + return; + } + + int remainder = ImageMaths.Modulo8(source.Length); + int adjustedCount = source.Length - remainder; + + if (adjustedCount > 0) + { + BulkConvertNormalizedFloatToByteClampOverflows(source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount)); + + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); } } @@ -57,7 +87,7 @@ namespace SixLabors.ImageSharp { GuardAvx2(nameof(BulkConvertByteToNormalizedFloat)); - DebugGuard.IsTrue((dest.Length % 8) == 0, nameof(source), "dest.Length should be divisable by 8!"); + DebugGuard.IsTrue(ImageMaths.Modulo8(dest.Length) == 0, nameof(source), "dest.Length should be divisable by 8!"); var bVec = new Vector(256.0f / 255.0f); var magicFloat = new Vector(32768.0f); @@ -93,30 +123,6 @@ namespace SixLabors.ImageSharp } } - /// - /// as much elements as possible, slicing them down (keeping the remainder). - /// - internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( - ref ReadOnlySpan source, - ref Span dest) - { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); - - if (IsAvailable) - { - int remainder = source.Length % Vector.Count; - int alignedCount = source.Length - remainder; - - if (alignedCount > 0) - { - BulkConvertNormalizedFloatToByteClampOverflows(source.Slice(0, alignedCount), dest.Slice(0, alignedCount)); - - source = source.Slice(alignedCount); - dest = dest.Slice(alignedCount); - } - } - } - /// /// Implementation of which is faster on older runtimes. /// @@ -124,7 +130,7 @@ namespace SixLabors.ImageSharp { GuardAvx2(nameof(BulkConvertNormalizedFloatToByteClampOverflows)); - DebugGuard.IsTrue((source.Length % 8) == 0, nameof(source), "source.Length should be divisible by 8!"); + DebugGuard.IsTrue(ImageMaths.Modulo8(source.Length) == 0, nameof(source), "source.Length should be divisible by 8!"); if (source.Length == 0) { @@ -174,7 +180,10 @@ namespace SixLabors.ImageSharp { GuardAvx2(nameof(BulkConvertNormalizedFloatToByte)); - DebugGuard.IsTrue((source.Length % Vector.Count) == 0, nameof(source), "source.Length should be divisable by Vector.Count!"); + DebugGuard.IsTrue( + ImageMaths.Modulo8(source.Length) == 0, + nameof(source), + "source.Length should be divisible by 8!"); if (source.Length == 0) { diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index 996a08fb4b..dfa6f189c8 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -28,27 +28,58 @@ namespace SixLabors.ImageSharp #endif /// - /// as much elements as possible, slicing them down (keeping the remainder). + /// as many elements as possible, slicing them down (keeping the remainder). /// - [Conditional("NETCOREAPP2_1")] + [MethodImpl(InliningOptions.ShortMethod)] internal static void BulkConvertByteToNormalizedFloatReduce( ref ReadOnlySpan source, ref Span dest) { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); - if (IsAvailable) + if (!IsAvailable) { - int remainder = source.Length % Vector.Count; - int alignedCount = source.Length - remainder; + return; + } + + int remainder = ImageMaths.ModuloP2(source.Length, Vector.Count); + int adjustedCount = source.Length - remainder; - if (alignedCount > 0) - { - BulkConvertByteToNormalizedFloat(source.Slice(0, alignedCount), dest.Slice(0, alignedCount)); + if (adjustedCount > 0) + { + BulkConvertByteToNormalizedFloat(source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount)); - source = source.Slice(alignedCount); - dest = dest.Slice(alignedCount); - } + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); + } + } + + /// + /// as many elements as possible, slicing them down (keeping the remainder). + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + + if (!IsAvailable) + { + return; + } + + int remainder = ImageMaths.ModuloP2(source.Length, Vector.Count); + int adjustedCount = source.Length - remainder; + + if (adjustedCount > 0) + { + BulkConvertNormalizedFloatToByteClampOverflows( + source.Slice(0, adjustedCount), + dest.Slice(0, adjustedCount)); + + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); } } @@ -58,7 +89,7 @@ namespace SixLabors.ImageSharp internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { DebugGuard.IsTrue( - dest.Length % Vector.Count == 0, + ImageMaths.ModuloP2(dest.Length, Vector.Count) == 0, nameof(source), "dest.Length should be divisible by Vector.Count!"); @@ -67,8 +98,6 @@ namespace SixLabors.ImageSharp ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); - var scale = new Vector(1f / 255f); - for (int i = 0; i < n; i++) { Vector b = Unsafe.Add(ref sourceBase, i); @@ -77,10 +106,10 @@ namespace SixLabors.ImageSharp Vector.Widen(s0, out Vector w0, out Vector w1); Vector.Widen(s1, out Vector w2, out Vector w3); - Vector f0 = ConvertToSingle(w0, scale); - Vector f1 = ConvertToSingle(w1, scale); - Vector f2 = ConvertToSingle(w2, scale); - Vector f3 = ConvertToSingle(w3, scale); + Vector f0 = ConvertToSingle(w0); + Vector f1 = ConvertToSingle(w1); + Vector f2 = ConvertToSingle(w2); + Vector f3 = ConvertToSingle(w3); ref Vector d = ref Unsafe.Add(ref destBase, i * 4); d = f0; @@ -90,31 +119,6 @@ namespace SixLabors.ImageSharp } } - /// - /// as much elements as possible, slicing them down (keeping the remainder). - /// - [Conditional("NETCOREAPP2_1")] - internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( - ref ReadOnlySpan source, - ref Span dest) - { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); - - if (IsAvailable) - { - int remainder = source.Length % Vector.Count; - int alignedCount = source.Length - remainder; - - if (alignedCount > 0) - { - BulkConvertNormalizedFloatToByteClampOverflows(source.Slice(0, alignedCount), dest.Slice(0, alignedCount)); - - source = source.Slice(alignedCount); - dest = dest.Slice(alignedCount); - } - } - } - /// /// Implementation of , which is faster on new .NET runtime. /// @@ -123,7 +127,7 @@ namespace SixLabors.ImageSharp Span dest) { DebugGuard.IsTrue( - dest.Length % Vector.Count == 0, + ImageMaths.ModuloP2(dest.Length, Vector.Count) == 0, nameof(dest), "dest.Length should be divisible by Vector.Count!"); @@ -168,11 +172,11 @@ namespace SixLabors.ImageSharp } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector ConvertToSingle(Vector u, Vector scale) + private static Vector ConvertToSingle(Vector u) { Vector vi = Vector.AsVectorInt32(u); Vector v = Vector.ConvertToSingle(vi); - v *= scale; + v *= new Vector(1f / 255f); return v; } } diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs index bb21474660..2d9f53eafa 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs @@ -1,71 +1,81 @@ -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +// ReSharper disable MemberHidesStaticFromOuterClass namespace SixLabors.ImageSharp { internal static partial class SimdUtils { /// /// Fallback implementation based on (128bit). - /// For , efficient software fallback implementations are present - /// + maybe even mono can emit intrinsics for that type :P + /// For , efficient software fallback implementations are present, + /// and we hope that even mono's JIT is able to emit SIMD instructions for that type :P /// public static class FallbackIntrinsics128 { /// - /// as much elements as possible, slicing them down (keeping the remainder). + /// as many elements as possible, slicing them down (keeping the remainder). /// + [MethodImpl(InliningOptions.ShortMethod)] internal static void BulkConvertByteToNormalizedFloatReduce( ref ReadOnlySpan source, ref Span dest) { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); - int remainder = source.Length % 4; - int alignedCount = source.Length - remainder; + int remainder = ImageMaths.Modulo4(source.Length); + int adjustedCount = source.Length - remainder; - if (alignedCount > 0) + if (adjustedCount > 0) { BulkConvertByteToNormalizedFloat( - source.Slice(0, alignedCount), - dest.Slice(0, alignedCount)); + source.Slice(0, adjustedCount), + dest.Slice(0, adjustedCount)); - source = source.Slice(alignedCount); - dest = dest.Slice(alignedCount); + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); } } /// - /// as much elements as possible, slicing them down (keeping the remainder). + /// as many elements as possible, slicing them down (keeping the remainder). /// + [MethodImpl(InliningOptions.ShortMethod)] internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( ref ReadOnlySpan source, ref Span dest) { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); - int remainder = source.Length % 4; - int alignedCount = source.Length - remainder; + int remainder = ImageMaths.Modulo4(source.Length); + int adjustedCount = source.Length - remainder; - if (alignedCount > 0) + if (adjustedCount > 0) { BulkConvertNormalizedFloatToByteClampOverflows( - source.Slice(0, alignedCount), - dest.Slice(0, alignedCount)); + source.Slice(0, adjustedCount), + dest.Slice(0, adjustedCount)); - source = source.Slice(alignedCount); - dest = dest.Slice(alignedCount); + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); } } /// /// Implementation of using . /// + [MethodImpl(InliningOptions.ColdPath)] internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { - DebugGuard.IsTrue((dest.Length % 4) == 0, nameof(dest), "dest.Length should be divisible by 4!"); + DebugGuard.IsTrue( + ImageMaths.Modulo4(dest.Length) == 0, + nameof(dest), + "dest.Length should be divisible by 4!"); int count = dest.Length / 4; if (count == 0) @@ -94,11 +104,15 @@ namespace SixLabors.ImageSharp /// /// Implementation of using . /// + [MethodImpl(InliningOptions.ColdPath)] internal static void BulkConvertNormalizedFloatToByteClampOverflows( ReadOnlySpan source, Span dest) { - DebugGuard.IsTrue((source.Length % 4) == 0, nameof(source), "source.Length should be divisible by 4!"); + DebugGuard.IsTrue( + ImageMaths.Modulo4(source.Length) == 0, + nameof(source), + "source.Length should be divisible by 4!"); int count = source.Length / 4; if (count == 0) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index bc75dc8caa..95a6030fd1 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -61,25 +62,22 @@ namespace SixLabors.ImageSharp /// /// The source span of bytes /// The destination span of floats + [MethodImpl(InliningOptions.ShortMethod)] internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); +#if NETCOREAPP2_1 ExtendedIntrinsics.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); +#else BasicIntrinsics256.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); +#endif FallbackIntrinsics128.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); // Deal with the remainder: - int count = source.Length; - if (count > 0) + if (source.Length > 0) { - // TODO: Do we need to optimize anything on this? (There are at most 7 remainders) - ref byte sBase = ref MemoryMarshal.GetReference(source); - ref float dBase = ref MemoryMarshal.GetReference(dest); - for (int i = 0; i < count; i++) - { - Unsafe.Add(ref dBase, i) = Unsafe.Add(ref sBase, i) / 255f; - } + ConverByteToNormalizedFloatRemainder(source, dest); } } @@ -91,35 +89,71 @@ namespace SixLabors.ImageSharp /// /// The source span of floats /// The destination span of bytes + [MethodImpl(InliningOptions.ShortMethod)] internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); +#if NETCOREAPP2_1 ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); +#else BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); +#endif FallbackIntrinsics128.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); // Deal with the remainder: - int count = source.Length; - if (count > 0) + if (source.Length > 0) { - ref float sBase = ref MemoryMarshal.GetReference(source); - ref byte dBase = ref MemoryMarshal.GetReference(dest); - - for (int i = 0; i < count; i++) - { - // TODO: Do we need to optimize anything on this? (There are at most 7 remainders) - float f = Unsafe.Add(ref sBase, i); - f *= 255f; - f += 0.5f; - f = MathF.Max(0, f); - f = MathF.Min(255f, f); - - Unsafe.Add(ref dBase, i) = (byte)f; - } + ConvertNormalizedFloatToByteRemainder(source, dest); } } + [MethodImpl(InliningOptions.ColdPath)] + private static void ConverByteToNormalizedFloatRemainder(ReadOnlySpan source, Span dest) + { + ref byte sBase = ref MemoryMarshal.GetReference(source); + ref float dBase = ref MemoryMarshal.GetReference(dest); + + // There are at most 3 elements at this point, having a for loop is overkill. + // Let's minimize the no. of instructions! + switch (source.Length) + { + case 3: + Unsafe.Add(ref dBase, 2) = Unsafe.Add(ref sBase, 2) / 255f; + goto case 2; + case 2: + Unsafe.Add(ref dBase, 1) = Unsafe.Add(ref sBase, 1) / 255f; + goto case 1; + case 1: + dBase = sBase / 255f; + break; + } + } + + [MethodImpl(InliningOptions.ColdPath)] + private static void ConvertNormalizedFloatToByteRemainder(ReadOnlySpan source, Span dest) + { + ref float sBase = ref MemoryMarshal.GetReference(source); + ref byte dBase = ref MemoryMarshal.GetReference(dest); + + switch (source.Length) + { + case 3: + Unsafe.Add(ref dBase, 2) = ConvertToByte(Unsafe.Add(ref sBase, 2)); + goto case 2; + case 2: + Unsafe.Add(ref dBase, 1) = ConvertToByte(Unsafe.Add(ref sBase, 1)); + goto case 1; + case 1: + dBase = ConvertToByte(sBase); + break; + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + private static byte ConvertToByte(float f) => (byte)ImageMaths.Clamp((f * 255f) + 0.5f, 0, 255f); + + [Conditional("DEBUG")] private static void GuardAvx2(string operation) { if (!IsAvx2CompatibleArchitecture) diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index a56082fcd3..eaa52a9750 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -99,30 +99,30 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } // RESULTS (2018 October): - // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | - // ------------------------------------------------------------------ |-------- |------ |-------------:|-------------:|-----------:|-------:|---------:|-------:|----------:| - // BasicBulk | Clr | 64 | 581.62 ns | 33.625 ns | 1.8999 ns | 2.27 | 0.02 | - | 0 B | - // BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 64 | 256.66 ns | 45.153 ns | 2.5512 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 64 | 201.92 ns | 30.161 ns | 1.7042 ns | 0.79 | 0.01 | - | 0 B | - // PixelOperations_Base | Clr | 64 | 665.01 ns | 13.032 ns | 0.7363 ns | 2.59 | 0.02 | 0.0067 | 24 B | - // PixelOperations_Specialized | Clr | 64 | 295.14 ns | 26.335 ns | 1.4880 ns | 1.15 | 0.01 | - | 0 B | - // | | | | | | | | | | - // BasicBulk | Core | 64 | 513.22 ns | 91.110 ns | 5.1479 ns | 3.19 | 0.03 | - | 0 B | - // BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows | Core | 64 | 160.76 ns | 2.760 ns | 0.1559 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Core | 64 | 95.98 ns | 10.077 ns | 0.5694 ns | 0.60 | 0.00 | - | 0 B | - // PixelOperations_Base | Core | 64 | 591.74 ns | 49.856 ns | 2.8170 ns | 3.68 | 0.01 | 0.0067 | 24 B | - // PixelOperations_Specialized | Core | 64 | 149.11 ns | 4.485 ns | 0.2534 ns | 0.93 | 0.00 | - | 0 B | - // | | | | | | | | | | - // BasicBulk | Clr | 2048 | 15,345.85 ns | 1,213.551 ns | 68.5679 ns | 3.90 | 0.01 | - | 0 B | - // BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 2048 | 3,939.49 ns | 71.101 ns | 4.0173 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 2048 | 2,272.61 ns | 110.671 ns | 6.2531 ns | 0.58 | 0.00 | - | 0 B | - // PixelOperations_Base | Clr | 2048 | 17,422.47 ns | 811.733 ns | 45.8644 ns | 4.42 | 0.01 | - | 24 B | - // PixelOperations_Specialized | Clr | 2048 | 3,984.26 ns | 110.352 ns | 6.2351 ns | 1.01 | 0.00 | - | 0 B | - // | | | | | | | | | | - // BasicBulk | Core | 2048 | 14,950.43 ns | 699.309 ns | 39.5123 ns | 3.76 | 0.02 | - | 0 B | - // BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows | Core | 2048 | 3,978.28 ns | 481.105 ns | 27.1833 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Core | 2048 | 2,169.54 ns | 75.606 ns | 4.2719 ns | !!0.55!| 0.00 | - | 0 B | - // PixelOperations_Base | Core | 2048 | 18,403.62 ns | 1,494.056 ns | 84.4169 ns | 4.63 | 0.03 | - | 24 B | - // PixelOperations_Specialized | Core | 2048 | 2,227.60 ns | 486.761 ns | 27.5029 ns | !!0.56!| 0.01 | - | 0 B | + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ---------------------------- |-------- |------ |-------------:|-------------:|------------:|-------:|---------:|-------:|----------:| + // FallbackIntrinsics128 | Clr | 64 | 340.38 ns | 22.319 ns | 1.2611 ns | 1.41 | 0.01 | - | 0 B | + // BasicIntrinsics256 | Clr | 64 | 240.79 ns | 11.421 ns | 0.6453 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic | Clr | 64 | 199.09 ns | 124.239 ns | 7.0198 ns | 0.83 | 0.02 | - | 0 B | + // PixelOperations_Base | Clr | 64 | 647.99 ns | 24.003 ns | 1.3562 ns | 2.69 | 0.01 | 0.0067 | 24 B | + // PixelOperations_Specialized | Clr | 64 | 259.79 ns | 13.391 ns | 0.7566 ns | 1.08 | 0.00 | - | 0 B | <--- ceremonial overhead has been minimized! + // | | | | | | | | | | + // FallbackIntrinsics128 | Core | 64 | 234.64 ns | 12.320 ns | 0.6961 ns | 1.58 | 0.00 | - | 0 B | + // BasicIntrinsics256 | Core | 64 | 148.87 ns | 2.794 ns | 0.1579 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic | Core | 64 | 94.06 ns | 10.015 ns | 0.5659 ns | 0.63 | 0.00 | - | 0 B | + // PixelOperations_Base | Core | 64 | 573.52 ns | 31.865 ns | 1.8004 ns | 3.85 | 0.01 | 0.0067 | 24 B | + // PixelOperations_Specialized | Core | 64 | 117.21 ns | 13.264 ns | 0.7494 ns | 0.79 | 0.00 | - | 0 B | + // | | | | | | | | | | + // FallbackIntrinsics128 | Clr | 2048 | 6,735.93 ns | 2,139.340 ns | 120.8767 ns | 1.71 | 0.03 | - | 0 B | + // BasicIntrinsics256 | Clr | 2048 | 3,929.29 ns | 334.027 ns | 18.8731 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic | Clr | 2048 | 2,226.01 ns | 130.525 ns | 7.3749 ns |!! 0.57 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! + // PixelOperations_Base | Clr | 2048 | 16,760.84 ns | 367.800 ns | 20.7814 ns | 4.27 | 0.02 | - | 24 B | <--- Extra copies using "Vector4 TPixel.ToVector4()" + // PixelOperations_Specialized | Clr | 2048 | 3,986.03 ns | 237.238 ns | 13.4044 ns | 1.01 | 0.00 | - | 0 B | <--- can't yet detect whether ExtendedIntrinsics are available :( + // | | | | | | | | | | + // FallbackIntrinsics128 | Core | 2048 | 6,644.65 ns | 2,677.090 ns | 151.2605 ns | 1.69 | 0.05 | - | 0 B | + // BasicIntrinsics256 | Core | 2048 | 3,923.70 ns | 1,971.760 ns | 111.4081 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic | Core | 2048 | 2,092.32 ns | 375.657 ns | 21.2253 ns |!! 0.53 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock! + // PixelOperations_Base | Core | 2048 | 16,875.73 ns | 1,271.957 ns | 71.8679 ns | 4.30 | 0.10 | - | 24 B | + // PixelOperations_Specialized | Core | 2048 | 2,129.92 ns | 262.888 ns | 14.8537 ns |!! 0.54 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock! } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 519edaa31f..2cbe549e4a 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -191,30 +191,30 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk // RESULTS (2018 October): // - // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | - // ---------------------------------------------------- |-------- |------ |------------:|-------------:|-----------:|-------:|---------:|-------:|----------:| - // BasicBulk | Clr | 64 | 267.40 ns | 30.711 ns | 1.7352 ns | 1.07 | 0.01 | - | 0 B | - // BasicIntrinsics256_BulkConvertByteToNormalizedFloat | Clr | 64 | 249.97 ns | 33.838 ns | 1.9119 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsics_BulkConvertByteToNormalizedFloat | Clr | 64 | 176.97 ns | 5.221 ns | 0.2950 ns | 0.71 | 0.00 | - | 0 B | - // PixelOperations_Base | Clr | 64 | 349.70 ns | 104.331 ns | 5.8949 ns | 1.40 | 0.02 | 0.0072 | 24 B | - // PixelOperations_Specialized | Clr | 64 | 288.31 ns | 26.833 ns | 1.5161 ns | 1.15 | 0.01 | - | 0 B | - // | | | | | | | | | | - // BasicBulk | Core | 64 | 185.36 ns | 30.051 ns | 1.6979 ns | 1.26 | 0.01 | - | 0 B | - // BasicIntrinsics256_BulkConvertByteToNormalizedFloat | Core | 64 | 146.84 ns | 12.674 ns | 0.7161 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsics_BulkConvertByteToNormalizedFloat | Core | 64 | 67.31 ns | 2.542 ns | 0.1436 ns | 0.46 | 0.00 | - | 0 B | - // PixelOperations_Base | Core | 64 | 272.03 ns | 94.419 ns | 5.3348 ns | 1.85 | 0.03 | 0.0072 | 24 B | - // PixelOperations_Specialized | Core | 64 | 121.91 ns | 31.477 ns | 1.7785 ns | 0.83 | 0.01 | - | 0 B | - // | | | | | | | | | | - // BasicBulk | Clr | 2048 | 5,133.04 ns | 284.052 ns | 16.0494 ns | 1.21 | 0.01 | - | 0 B | - // BasicIntrinsics256_BulkConvertByteToNormalizedFloat | Clr | 2048 | 4,248.58 ns | 1,095.887 ns | 61.9196 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsics_BulkConvertByteToNormalizedFloat | Clr | 2048 | 1,214.02 ns | 184.349 ns | 10.4160 ns | 0.29 | 0.00 | - | 0 B | - // PixelOperations_Base | Clr | 2048 | 7,096.04 ns | 362.350 ns | 20.4734 ns | 1.67 | 0.02 | - | 24 B | - // PixelOperations_Specialized | Clr | 2048 | 4,314.19 ns | 204.964 ns | 11.5809 ns | 1.02 | 0.01 | - | 0 B | - // | | | | | | | | | | - // BasicBulk | Core | 2048 | 5,038.38 ns | 223.282 ns | 12.6158 ns | 1.20 | 0.01 | - | 0 B | - // BasicIntrinsics256_BulkConvertByteToNormalizedFloat | Core | 2048 | 4,199.17 ns | 897.985 ns | 50.7378 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsics_BulkConvertByteToNormalizedFloat | Core | 2048 | 1,113.86 ns | 64.799 ns | 3.6613 ns | !!0.27!| 0.00 | - | 0 B | - // PixelOperations_Base | Core | 2048 | 7,015.00 ns | 920.083 ns | 51.9864 ns | 1.67 | 0.02 | - | 24 B | - // PixelOperations_Specialized | Core | 2048 | 1,176.59 ns | 256.955 ns | 14.5184 ns | !!0.28!| 0.00 | - | 0 B | + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ---------------------------- |-------- |------ |------------:|-------------:|------------:|-------:|---------:|-------:|----------:| + // FallbackIntrinsics128 | Clr | 64 | 287.62 ns | 6.026 ns | 0.3405 ns | 1.19 | 0.00 | - | 0 B | + // BasicIntrinsics256 | Clr | 64 | 240.83 ns | 10.585 ns | 0.5981 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Clr | 64 | 168.28 ns | 11.478 ns | 0.6485 ns | 0.70 | 0.00 | - | 0 B | + // PixelOperations_Base | Clr | 64 | 334.08 ns | 38.048 ns | 2.1498 ns | 1.39 | 0.01 | 0.0072 | 24 B | + // PixelOperations_Specialized | Clr | 64 | 255.41 ns | 10.939 ns | 0.6181 ns | 1.06 | 0.00 | - | 0 B | <--- ceremonial overhead has been minimized! + // | | | | | | | | | | + // FallbackIntrinsics128 | Core | 64 | 183.29 ns | 8.931 ns | 0.5046 ns | 1.32 | 0.00 | - | 0 B | + // BasicIntrinsics256 | Core | 64 | 139.18 ns | 7.633 ns | 0.4313 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Core | 64 | 66.29 ns | 16.366 ns | 0.9247 ns | 0.48 | 0.01 | - | 0 B | + // PixelOperations_Base | Core | 64 | 257.75 ns | 16.959 ns | 0.9582 ns | 1.85 | 0.01 | 0.0072 | 24 B | + // PixelOperations_Specialized | Core | 64 | 90.14 ns | 9.955 ns | 0.5625 ns | 0.65 | 0.00 | - | 0 B | + // | | | | | | | | | | + // FallbackIntrinsics128 | Clr | 2048 | 5,011.84 ns | 347.991 ns | 19.6621 ns | 1.22 | 0.01 | - | 0 B | + // BasicIntrinsics256 | Clr | 2048 | 4,119.35 ns | 720.153 ns | 40.6900 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Clr | 2048 | 1,195.29 ns | 164.389 ns | 9.2883 ns |!! 0.29 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! + // PixelOperations_Base | Clr | 2048 | 6,820.58 ns | 823.433 ns | 46.5255 ns | 1.66 | 0.02 | - | 24 B | + // PixelOperations_Specialized | Clr | 2048 | 4,203.53 ns | 176.714 ns | 9.9847 ns | 1.02 | 0.01 | - | 0 B | <--- can't yet detect whether ExtendedIntrinsics are available :( + // | | | | | | | | | | + // FallbackIntrinsics128 | Core | 2048 | 5,017.89 ns | 4,021.533 ns | 227.2241 ns | 1.24 | 0.05 | - | 0 B | + // BasicIntrinsics256 | Core | 2048 | 4,046.51 ns | 1,150.390 ns | 64.9992 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Core | 2048 | 1,130.59 ns | 832.588 ns | 47.0427 ns |!! 0.28 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock! + // PixelOperations_Base | Core | 2048 | 6,752.68 ns | 272.820 ns | 15.4148 ns | 1.67 | 0.02 | - | 24 B | + // PixelOperations_Specialized | Core | 2048 | 1,126.13 ns | 79.192 ns | 4.4745 ns |!! 0.28 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Abs.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs similarity index 88% rename from tests/ImageSharp.Benchmarks/General/Abs.cs rename to tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs index a67f3f1078..ea53959b6a 100644 --- a/tests/ImageSharp.Benchmarks/General/Abs.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs @@ -1,9 +1,9 @@ -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System; +using System; - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath +{ public class Abs { [Params(-1, 1)] diff --git a/tests/ImageSharp.Benchmarks/General/Clamp.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/Clamp.cs similarity index 94% rename from tests/ImageSharp.Benchmarks/General/Clamp.cs rename to tests/ImageSharp.Benchmarks/General/BasicMath/Clamp.cs index ef6bc3c402..d486cb2f37 100644 --- a/tests/ImageSharp.Benchmarks/General/Clamp.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/Clamp.cs @@ -3,13 +3,13 @@ // Licensed under the Apache License, Version 2.0. // -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System; - using System.Runtime.CompilerServices; +using System; +using System.Runtime.CompilerServices; - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath +{ public class Clamp { [Params(-1, 0, 255, 256)] diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoConstant.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoConstant.cs new file mode 100644 index 0000000000..9ddfad7222 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoConstant.cs @@ -0,0 +1,23 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes.Jobs; + +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath +{ + [LongRunJob] + public class ModuloPowerOfTwoConstant + { + private readonly int value = 42; + + [Benchmark(Baseline = true)] + public int Standard() + { + return this.value % 8; + } + + [Benchmark] + public int Bitwise() + { + return ImageMaths.Modulo8(this.value); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoVariable.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoVariable.cs new file mode 100644 index 0000000000..5c2fe81fa2 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoVariable.cs @@ -0,0 +1,32 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes.Jobs; + +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath +{ + [LongRunJob] + public class ModuloPowerOfTwoVariable + { + private readonly int value = 42; + + private readonly int m = 32; + + [Benchmark(Baseline = true)] + public int Standard() + { + return this.value % this.m; + } + + [Benchmark] + public int Bitwise() + { + return ImageMaths.ModuloP2(this.value, this.m); + } + + // RESULTS: + // + // Method | Mean | Error | StdDev | Median | Scaled | ScaledSD | + // --------- |----------:|----------:|----------:|----------:|-------:|---------:| + // Standard | 1.2465 ns | 0.0093 ns | 0.0455 ns | 1.2423 ns | 1.00 | 0.00 | + // Bitwise | 0.0265 ns | 0.0103 ns | 0.0515 ns | 0.0000 ns | 0.02 | 0.04 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Pow.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs similarity index 93% rename from tests/ImageSharp.Benchmarks/General/Pow.cs rename to tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs index 325bd9d20e..0f256fc781 100644 --- a/tests/ImageSharp.Benchmarks/General/Pow.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs @@ -1,7 +1,8 @@ using System; + using BenchmarkDotNet.Attributes; -namespace SixLabors.ImageSharp.Benchmarks.General +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath { public class Pow { diff --git a/tests/ImageSharp.Benchmarks/General/Modulus.cs b/tests/ImageSharp.Benchmarks/General/Modulus.cs deleted file mode 100644 index e6d5ccce62..0000000000 --- a/tests/ImageSharp.Benchmarks/General/Modulus.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using BenchmarkDotNet.Attributes; - - public class Modulus - { - [Benchmark(Baseline = true, Description = "Standard Modulus using %")] - public int StandardModulus() - { - return 255 % 256; - } - - [Benchmark(Description = "Bitwise Modulus using &")] - public int BitwiseModulus() - { - return 255 & 255; - } - } -} diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index feefd17580..c63cb3438f 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -264,13 +264,26 @@ namespace SixLabors.ImageSharp.Tests.Common TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, (s, d) => SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span) ); + + // for small values, let's stress test the implementation a bit: + if (count > 0 && count < 10) + { + for (int i = 0; i < 20; i++) + { + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows( + count, + (s, d) => SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span), + i + 42); + } + } } private static void TestImpl_BulkConvertNormalizedFloatToByteClampOverflows( int count, - Action, Memory> convert) + Action, Memory> convert, int seed = -1) { - float[] source = new Random(count).GenerateRandomFloatArray(count, -0.1f, 1.2f); + seed = seed > 0 ? seed : count; + float[] source = new Random(seed).GenerateRandomFloatArray(count, -0.2f, 1.2f); byte[] expected = source.Select(NormalizedFloatToByte).ToArray(); byte[] actual = new byte[count]; diff --git a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs index aec4d0b810..d8b1525bed 100644 --- a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs @@ -10,56 +10,70 @@ namespace SixLabors.ImageSharp.Tests.Helpers public class ImageMathsTests { [Theory] - [InlineData(0, 0)] - [InlineData(1, 1)] - [InlineData(2, 2)] - [InlineData(3, 3)] - [InlineData(4, 0)] - [InlineData(100, 0)] - [InlineData(123, 3)] - [InlineData(53436353, 1)] - public void Modulo4(int a, int expected) + [InlineData(0)] + [InlineData(1)] + [InlineData(2)] + [InlineData(3)] + [InlineData(4)] + [InlineData(100)] + [InlineData(123)] + [InlineData(53436353)] + public void Modulo4(int x) { - int actual = ImageMaths.Modulo4(a); - Assert.Equal(expected, actual); + int actual = ImageMaths.Modulo4(x); + Assert.Equal(x % 4, actual); } [Theory] - [InlineData(0, 0)] - [InlineData(1, 1)] + [InlineData(0)] + [InlineData(1)] + [InlineData(2)] + [InlineData(6)] + [InlineData(7)] + [InlineData(8)] + [InlineData(100)] + [InlineData(123)] + [InlineData(53436353)] + [InlineData(975)] + public void Modulo8(int x) + { + int actual = ImageMaths.Modulo8(x); + Assert.Equal(x % 8, actual); + } + + [Theory] + [InlineData(0, 2)] + [InlineData(1, 2)] [InlineData(2, 2)] - [InlineData(6, 6)] - [InlineData(7, 7)] - [InlineData(8, 0)] - [InlineData(100, 4)] - [InlineData(123, 3)] - [InlineData(53436353, 1)] - [InlineData(975, 7)] - public void Modulo8(int a, int expected) + [InlineData(0, 4)] + [InlineData(3, 4)] + [InlineData(5, 4)] + [InlineData(5, 8)] + [InlineData(8, 8)] + [InlineData(8, 16)] + [InlineData(15, 16)] + [InlineData(17, 16)] + [InlineData(17, 32)] + [InlineData(31, 32)] + [InlineData(32, 32)] + [InlineData(33, 32)] + public void Modulo2P(int x, int m) { - int actual = ImageMaths.Modulo8(a); - Assert.Equal(expected, actual); + int actual = ImageMaths.ModuloP2(x, m); + Assert.Equal(x % m, actual); } [Theory] - [InlineData(0, 2, 0)] - [InlineData(1, 2, 1)] - [InlineData(2, 2, 0)] - [InlineData(0, 4, 0)] - [InlineData(3, 4, 3)] - [InlineData(5, 4, 1)] - [InlineData(5, 8, 5)] - [InlineData(8, 8, 0)] - [InlineData(8, 16, 8)] - [InlineData(15, 16, 15)] - [InlineData(17, 16, 1)] - [InlineData(17, 32, 17)] - [InlineData(31, 32, 31)] - [InlineData(32, 32, 0)] - [InlineData(33, 32, 1)] - public void Modulo2P(int a, int m, int expected) + [InlineData(0, 0, 0, 0)] + [InlineData(0.5f, 0, 1, 0.5f)] + [InlineData(-0.5f, -0.1f, 10, -0.1f)] + [InlineData(-0.05f, -0.1f, 10, -0.05f)] + [InlineData(9.9f, -0.1f, 10, 9.9f)] + [InlineData(10f, -0.1f, 10, 10f)] + [InlineData(10.1f, -0.1f, 10, 10f)] + public void Clamp(float x, float min, float max, float expected) { - int actual = ImageMaths.ModuloP2(a, m); + float actual = ImageMaths.Clamp(x, min, max); Assert.Equal(expected, actual); } From 520c6fc564c7748f73e9e7e64c483f48f0e2490f Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 21 Oct 2018 21:09:40 +0200 Subject: [PATCH 184/381] fix comment --- .../Common/Helpers/SimdUtils.FallbackIntrinsics128.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs index 2d9f53eafa..ab18a00679 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs @@ -132,7 +132,7 @@ namespace SixLabors.ImageSharp s *= maxBytes; s += half; - // I'm not sure if Clamp() is properly implemented with intrinsics. + // I'm not sure if Vector4.Clamp() is properly implemented with intrinsics. s = Vector4.Max(Vector4.Zero, s); s = Vector4.Min(maxBytes, s); From 5c687fa004e32ff8114c58e309070fc2f4ea2ca5 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 21 Oct 2018 23:38:12 +0200 Subject: [PATCH 185/381] address review findings + some more cleanup --- .../Helpers/SimdUtils.BasicIntrinsics256.cs | 28 ++++++++----------- .../Helpers/SimdUtils.ExtendedIntrinsics.cs | 14 +++------- .../SimdUtils.FallbackIntrinsics128.cs | 14 +++------- src/ImageSharp/Common/Helpers/SimdUtils.cs | 22 ++++++++++++++- src/ImageSharp/Common/Tuples/Octet.cs | 13 +++++++-- src/ImageSharp/Common/Tuples/Vector4Pair.cs | 10 +++---- .../JpegColorConverter.FromYCbCrSimd.cs | 2 +- .../JpegColorConverter.FromYCbCrSimdAvx2.cs | 2 +- .../ColorConverters/JpegColorConverter.cs | 4 +-- .../PixelFormats/PixelOperations{TPixel}.cs | 10 +++---- 10 files changed, 64 insertions(+), 55 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs index 713d606e79..0f1ce2ab6a 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp ref ReadOnlySpan source, ref Span dest) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); if (!IsAvailable) { @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp ref ReadOnlySpan source, ref Span dest) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); if (!IsAvailable) { @@ -78,16 +78,15 @@ namespace SixLabors.ImageSharp /// /// SIMD optimized implementation for . - /// Works only with `dest.Length` divisible by 8. + /// Works only with span Length divisible by 8. /// Implementation adapted from: /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions /// http://stackoverflow.com/a/536278 /// internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { - GuardAvx2(nameof(BulkConvertByteToNormalizedFloat)); - - DebugGuard.IsTrue(ImageMaths.Modulo8(dest.Length) == 0, nameof(source), "dest.Length should be divisable by 8!"); + VerifyIsAvx2Compatible(nameof(BulkConvertByteToNormalizedFloat)); + VerifySpanInput(source, dest, 8); var bVec = new Vector(256.0f / 255.0f); var magicFloat = new Vector(32768.0f); @@ -128,9 +127,8 @@ namespace SixLabors.ImageSharp /// internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) { - GuardAvx2(nameof(BulkConvertNormalizedFloatToByteClampOverflows)); - - DebugGuard.IsTrue(ImageMaths.Modulo8(source.Length) == 0, nameof(source), "source.Length should be divisible by 8!"); + VerifyIsAvx2Compatible(nameof(BulkConvertNormalizedFloatToByteClampOverflows)); + VerifySpanInput(source, dest, 8); if (source.Length == 0) { @@ -168,9 +166,9 @@ namespace SixLabors.ImageSharp } /// - /// Convert 'source.Length' values normalized into [0..1] from 'source' + /// Convert all values normalized into [0..1] from 'source' /// into 'dest' buffer of . The values are scaled up into [0-255] and rounded. - /// The implementation is SIMD optimized and works only with `source.Length` divisible by 8. + /// This implementation is SIMD optimized and works only when span Length is divisible by 8. /// Based on: /// /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions @@ -178,12 +176,8 @@ namespace SixLabors.ImageSharp /// internal static void BulkConvertNormalizedFloatToByte(ReadOnlySpan source, Span dest) { - GuardAvx2(nameof(BulkConvertNormalizedFloatToByte)); - - DebugGuard.IsTrue( - ImageMaths.Modulo8(source.Length) == 0, - nameof(source), - "source.Length should be divisible by 8!"); + VerifyIsAvx2Compatible(nameof(BulkConvertNormalizedFloatToByte)); + VerifySpanInput(source, dest, 8); if (source.Length == 0) { diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index dfa6f189c8..e0d6187dca 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp ref ReadOnlySpan source, ref Span dest) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); if (!IsAvailable) { @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp ref ReadOnlySpan source, ref Span dest) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); if (!IsAvailable) { @@ -88,10 +88,7 @@ namespace SixLabors.ImageSharp /// internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { - DebugGuard.IsTrue( - ImageMaths.ModuloP2(dest.Length, Vector.Count) == 0, - nameof(source), - "dest.Length should be divisible by Vector.Count!"); + VerifySpanInput(source, dest, Vector.Count); int n = dest.Length / Vector.Count; @@ -126,10 +123,7 @@ namespace SixLabors.ImageSharp ReadOnlySpan source, Span dest) { - DebugGuard.IsTrue( - ImageMaths.ModuloP2(dest.Length, Vector.Count) == 0, - nameof(dest), - "dest.Length should be divisible by Vector.Count!"); + VerifySpanInput(source, dest, Vector.Count); int n = dest.Length / Vector.Count; diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs index ab18a00679..565ea08f5d 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp ref ReadOnlySpan source, ref Span dest) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); int remainder = ImageMaths.Modulo4(source.Length); int adjustedCount = source.Length - remainder; @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp ref ReadOnlySpan source, ref Span dest) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); int remainder = ImageMaths.Modulo4(source.Length); int adjustedCount = source.Length - remainder; @@ -72,10 +72,7 @@ namespace SixLabors.ImageSharp [MethodImpl(InliningOptions.ColdPath)] internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { - DebugGuard.IsTrue( - ImageMaths.Modulo4(dest.Length) == 0, - nameof(dest), - "dest.Length should be divisible by 4!"); + VerifySpanInput(source, dest, 4); int count = dest.Length / 4; if (count == 0) @@ -109,10 +106,7 @@ namespace SixLabors.ImageSharp ReadOnlySpan source, Span dest) { - DebugGuard.IsTrue( - ImageMaths.Modulo4(source.Length) == 0, - nameof(source), - "source.Length should be divisible by 4!"); + VerifySpanInput(source, dest, 4); int count = source.Length / 4; if (count == 0) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index 95a6030fd1..fade8da799 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -154,12 +154,32 @@ namespace SixLabors.ImageSharp private static byte ConvertToByte(float f) => (byte)ImageMaths.Clamp((f * 255f) + 0.5f, 0, 255f); [Conditional("DEBUG")] - private static void GuardAvx2(string operation) + private static void VerifyIsAvx2Compatible(string operation) { if (!IsAvx2CompatibleArchitecture) { throw new NotSupportedException($"{operation} is supported only on AVX2 CPU!"); } } + + [Conditional("DEBUG")] + private static void VerifySpanInput(ReadOnlySpan source, Span dest, int shouldBeDivisibleBy) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + DebugGuard.IsTrue( + ImageMaths.ModuloP2(dest.Length, shouldBeDivisibleBy) == 0, + nameof(source), + $"length should be divisable by {shouldBeDivisibleBy}!"); + } + + [Conditional("DEBUG")] + private static void VerifySpanInput(ReadOnlySpan source, Span dest, int shouldBeDivisibleBy) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + DebugGuard.IsTrue( + ImageMaths.ModuloP2(dest.Length, shouldBeDivisibleBy) == 0, + nameof(source), + $"length should be divisable by {shouldBeDivisibleBy}!"); + } } } \ No newline at end of file diff --git a/src/ImageSharp/Common/Tuples/Octet.cs b/src/ImageSharp/Common/Tuples/Octet.cs index ae01a31217..539b74e324 100644 --- a/src/ImageSharp/Common/Tuples/Octet.cs +++ b/src/ImageSharp/Common/Tuples/Octet.cs @@ -3,8 +3,14 @@ using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.Tuples { + /// + /// Contains 8 element value tuples of various types. + /// internal static class Octet { + /// + /// Value tuple of -s + /// [StructLayout(LayoutKind.Explicit, Size = 8 * sizeof(uint))] public struct OfUInt32 { @@ -34,7 +40,7 @@ namespace SixLabors.ImageSharp.Tuples public override string ToString() { - return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]"; + return $"{nameof(Octet)}.{nameof(OfUInt32)}({this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7})"; } [MethodImpl(InliningOptions.ShortMethod)] @@ -51,6 +57,9 @@ namespace SixLabors.ImageSharp.Tuples } } + /// + /// Value tuple of -s + /// [StructLayout(LayoutKind.Explicit, Size = 8)] public struct OfByte { @@ -80,7 +89,7 @@ namespace SixLabors.ImageSharp.Tuples public override string ToString() { - return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]"; + return $"{nameof(Octet)}.{nameof(OfByte)}({this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7})"; } [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/Common/Tuples/Vector4Pair.cs b/src/ImageSharp/Common/Tuples/Vector4Pair.cs index 5988b2200b..cae283d628 100644 --- a/src/ImageSharp/Common/Tuples/Vector4Pair.cs +++ b/src/ImageSharp/Common/Tuples/Vector4Pair.cs @@ -7,6 +7,7 @@ namespace SixLabors.ImageSharp.Tuples /// /// Its faster to process multiple Vector4-s together, so let's pair them! /// On AVX2 this pair should be convertible to of ! + /// TODO: Investigate defining this as union with an Octet.OfSingle type. /// [StructLayout(LayoutKind.Sequential)] internal struct Vector4Pair @@ -15,8 +16,6 @@ namespace SixLabors.ImageSharp.Tuples public Vector4 B; - private static readonly Vector4 Scale = new Vector4(1 / 255f); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public void MultiplyInplace(float value) { @@ -52,8 +51,9 @@ namespace SixLabors.ImageSharp.Tuples b = b.FastRound(); // Downscale by 1/255 - this.A *= Scale; - this.B *= Scale; + var scale = new Vector4(1 / 255f); + this.A *= scale; + this.B *= scale; } /// @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Tuples public override string ToString() { - return $"{this.A}, {this.B}"; + return $"{nameof(Vector4Pair)}({this.A}, {this.B})"; } } } \ No newline at end of file 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 5c63a478db..1dc72aaf5b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs @@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order: ref Vector4Octet destination = ref Unsafe.Add(ref resultBase, i); - destination.Collect(ref r, ref g, ref b); + destination.Pack(ref r, ref g, ref b); } } } 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 3f26cdc907..46644258b1 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs @@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order: ref Vector4Octet destination = ref Unsafe.Add(ref resultBase, i); - destination.Collect(ref rr, ref gg, ref bb); + destination.Pack(ref rr, ref gg, ref bb); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs index 293f3bc1f7..456636dc39 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs @@ -157,9 +157,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters public Vector4 V0, V1, V2, V3, V4, V5, V6, V7; /// - /// Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order. + /// Pack (r0,r1...r7) (g0,g1...g7) (b0,b1...b7) vector values as (r0,g0,b0,1), (r1,g1,b1,1) ... /// - public void Collect(ref Vector4Pair r, ref Vector4Pair g, ref Vector4Pair b) + public void Pack(ref Vector4Pair r, ref Vector4Pair g, ref Vector4Pair b) { this.V0.X = r.A.X; this.V0.Y = g.A.X; diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index cbf164a71c..6c133191a1 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -30,11 +30,10 @@ namespace SixLabors.ImageSharp.PixelFormats internal virtual void PackFromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) { ReadOnlySpan sourceVectors1 = sourceVectors; - Span destinationColors1 = destinationColors; - GuardSpans(sourceVectors1, nameof(sourceVectors1), destinationColors1, nameof(destinationColors1), count); + GuardSpans(sourceVectors1, nameof(sourceVectors1), destinationColors, nameof(destinationColors), count); ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors1); - ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors1); + ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); for (int i = 0; i < count; i++) { @@ -53,11 +52,10 @@ namespace SixLabors.ImageSharp.PixelFormats internal virtual void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) { ReadOnlySpan sourceColors1 = sourceColors; - Span destinationVectors1 = destinationVectors; - GuardSpans(sourceColors1, nameof(sourceColors1), destinationVectors1, nameof(destinationVectors1), count); + GuardSpans(sourceColors1, nameof(sourceColors1), destinationVectors, nameof(destinationVectors), count); ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors1); - ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors1); + ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); for (int i = 0; i < count; i++) { From 54ccf05794fb7a80c8a03572ab0f7ae5560d4714 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 00:03:12 +0200 Subject: [PATCH 186/381] drop slow Clamp() implementation --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 3 - src/ImageSharp/Common/Helpers/SimdUtils.cs | 6 +- .../General/BasicMath/ClampFloat.cs | 70 +++++++++++++++++++ .../{Clamp.cs => ClampInt32IntoByte.cs} | 2 +- .../Helpers/ImageMathsTests.cs | 2 +- 5 files changed, 75 insertions(+), 8 deletions(-) create mode 100644 tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs rename tests/ImageSharp.Benchmarks/General/BasicMath/{Clamp.cs => ClampInt32IntoByte.cs} (98%) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 1395975ec8..02a2e9ee55 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -61,9 +61,6 @@ namespace SixLabors.ImageSharp return x & (m - 1); } - [MethodImpl(InliningOptions.ShortMethod)] - public static float Clamp(float x, float min, float max) => Math.Min(max, Math.Max(min, x)); - /// /// Returns the absolute value of a 32-bit signed integer. Uses bit shifting to speed up the operation. /// diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index fade8da799..737e620061 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp [MethodImpl(InliningOptions.ShortMethod)] internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); #if NETCOREAPP2_1 ExtendedIntrinsics.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); @@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp [MethodImpl(InliningOptions.ShortMethod)] internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); #if NETCOREAPP2_1 ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp } [MethodImpl(InliningOptions.ShortMethod)] - private static byte ConvertToByte(float f) => (byte)ImageMaths.Clamp((f * 255f) + 0.5f, 0, 255f); + private static byte ConvertToByte(float f) => (byte)ComparableExtensions.Clamp((f * 255f) + 0.5f, 0, 255f); [Conditional("DEBUG")] private static void VerifyIsAvx2Compatible(string operation) diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs new file mode 100644 index 0000000000..3b7dea0955 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs @@ -0,0 +1,70 @@ +using System; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath +{ + public class ClampFloat + { + private readonly float min = -1.5f; + private readonly float max = 2.5f; + private static readonly float[] Values = { -10, -5, -3, -1.5f, -0.5f, 0f, 1f, 1.5f, 2.5f, 3, 10 }; + + [Benchmark(Baseline = true)] + public float UsingMathF() + { + float acc = 0; + + for (int i = 0; i < Values.Length; i++) + { + acc += ClampUsingMathF(Values[i], this.min, this.max); + } + + return acc; + } + + [Benchmark] + public float UsingBranching() + { + float acc = 0; + + for (int i = 0; i < Values.Length; i++) + { + acc += ClampUsingBranching(Values[i], this.min, this.max); + } + + return acc; + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float ClampUsingMathF(float x, float min, float max) + { + return Math.Min(max, Math.Max(min, x)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float ClampUsingBranching(float x, float min, float max) + { + if (x >= max) + { + return max; + } + + if (x <= min) + { + return min; + } + + return x; + } + + // RESULTS: + // Method | Mean | Error | StdDev | Scaled | + // --------------- |---------:|----------:|----------:|-------:| + // UsingMathF | 30.37 ns | 0.3764 ns | 0.3337 ns | 1.00 | + // UsingBranching | 18.66 ns | 0.1043 ns | 0.0871 ns | 0.61 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/Clamp.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs similarity index 98% rename from tests/ImageSharp.Benchmarks/General/BasicMath/Clamp.cs rename to tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs index d486cb2f37..6ce82ba115 100644 --- a/tests/ImageSharp.Benchmarks/General/BasicMath/Clamp.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs @@ -10,7 +10,7 @@ using BenchmarkDotNet.Attributes; namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath { - public class Clamp + public class ClampInt32IntoByte { [Params(-1, 0, 255, 256)] public int Value { get; set; } diff --git a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs index d8b1525bed..75ef611a5c 100644 --- a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers [InlineData(10.1f, -0.1f, 10, 10f)] public void Clamp(float x, float min, float max, float expected) { - float actual = ImageMaths.Clamp(x, min, max); + float actual = x.Clamp(min, max); Assert.Equal(expected, actual); } From 90c7153a6ebd8e4c8d0c24a0837d1f7aa7c340c2 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 00:05:47 +0200 Subject: [PATCH 187/381] remove useless reassignment in PixelOperations{TPixel} --- src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 6c133191a1..b12a2bfa58 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -29,10 +29,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void PackFromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) { - ReadOnlySpan sourceVectors1 = sourceVectors; - GuardSpans(sourceVectors1, nameof(sourceVectors1), destinationColors, nameof(destinationColors), count); + GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); - ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors1); + ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); for (int i = 0; i < count; i++) @@ -51,10 +50,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) { - ReadOnlySpan sourceColors1 = sourceColors; - GuardSpans(sourceColors1, nameof(sourceColors1), destinationVectors, nameof(destinationVectors), count); + GuardSpans(sourceColors, nameof(sourceColors), destinationVectors, nameof(destinationVectors), count); - ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors1); + ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); for (int i = 0; i < count; i++) From 876f230a84435fa7b388956fe63922cad48421b9 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 00:47:23 +0200 Subject: [PATCH 188/381] fix PixelOperationsTests --- .../PixelFormats/PixelOperationsTests.cs | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 651e63bdf7..8a0aee1a7c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -15,15 +15,17 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { public class PixelOperationsTests { - public class Argb32OperationsTests : PixelOperationsTests - { - public const string SkipProfilingBenchmarks = + public const string SkipProfilingBenchmarks = #if true - "Profiling benchmark - enable manually!"; + "Profiling benchmark - enable manually!"; #else null; #endif + public class Argb32OperationsTests : PixelOperationsTests + { + + public Argb32OperationsTests(ITestOutputHelper output) : base(output) { } @@ -39,8 +41,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { } - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - [Fact] public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); } @@ -52,8 +52,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { } - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - [Fact] public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); } @@ -65,8 +63,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { } - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - [Fact] public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); @@ -163,8 +159,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { } - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - [Fact] public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); @@ -261,11 +255,10 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { } - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - [Fact] public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + [Fact(Skip = SkipProfilingBenchmarks)] public void Benchmark_ToVector4() { const int times = 200000; @@ -288,8 +281,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { } - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - [Fact] public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); } @@ -301,8 +292,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { } - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - [Fact] public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); } From 6289a87e6d0ad5e4d1fda4385ea7fc722d1d56cb Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 01:28:23 +0200 Subject: [PATCH 189/381] Better benchmarks for ToVector4() proving that the current API is fine --- .../PixelConversion/PixelConversion_ConvertToVector4.cs | 8 ++++---- ...ersion_ConvertToVector4_AsPartOfCompositeOperation.cs | 8 ++++---- .../General/PixelConversion/TestRgba.cs | 9 ++++----- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs index 29a1139912..2bc3ee9716 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs @@ -75,9 +75,9 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion } // RESULTS: - // Method | Count | Mean | Error | StdDev | Scaled | - // ---------- |------ |---------:|----------:|----------:|-------:| - // UseRetval | 32 | 94.99 ns | 1.1199 ns | 0.9352 ns | 1.00 | - // UseCopyTo | 32 | 59.47 ns | 0.6104 ns | 0.5710 ns | 0.63 | + // Method | Count | Mean | Error | StdDev | Scaled | + // ---------- |------ |---------:|---------:|---------:|-------:| + // UseRetval | 32 | 109.0 ns | 1.202 ns | 1.125 ns | 1.00 | + // UseCopyTo | 32 | 108.6 ns | 1.151 ns | 1.020 ns | 1.00 | } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs index e5eb5c6cad..c6daf0f1e2 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs @@ -87,9 +87,9 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion } // RESULTS: - // Method | Count | Mean | Error | StdDev | Scaled | - // ---------- |------ |----------:|----------:|----------:|-------:| - // UseRetval | 32 | 100.35 ns | 0.4844 ns | 0.4532 ns | 1.00 | - // UseCopyTo | 32 | 53.95 ns | 0.1269 ns | 0.1125 ns | 0.54 | + // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | + // ---------- |------ |---------:|---------:|---------:|-------:|---------:| + // UseRetval | 32 | 120.2 ns | 1.560 ns | 1.383 ns | 1.00 | 0.00 | + // UseCopyTo | 32 | 121.7 ns | 2.439 ns | 2.281 ns | 1.01 | 0.02 | } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs index 3da7fcc4cf..cc8cf352a8 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs @@ -57,16 +57,15 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 ToVector4() { - return new Vector4(this.r, this.g, this.b, this.a); + return new Vector4(this.r, this.g, this.b, this.a) * new Vector4(1f / 255f); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void CopyToVector4(ref Vector4 dest) { - dest.X = this.r; - dest.Y = this.g; - dest.Z = this.b; - dest.W = this.a; + var tmp = new Vector4(this.r, this.g, this.b, this.a); + tmp *= new Vector4(1f / 255f); + dest = tmp; } } } \ No newline at end of file From c0aa91d232862852f60d0dfe47ab8a3a5a1a5218 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 01:45:21 +0200 Subject: [PATCH 190/381] refactored ToRgba32() on most pixel types --- src/ImageSharp/PixelFormats/Alpha8.cs | 6 +- src/ImageSharp/PixelFormats/Argb32.cs | 8 +- src/ImageSharp/PixelFormats/Bgr24.cs | 8 +- src/ImageSharp/PixelFormats/Bgr565.cs | 5 +- src/ImageSharp/PixelFormats/Bgra32.cs | 8 +- src/ImageSharp/PixelFormats/Bgra4444.cs | 5 +- src/ImageSharp/PixelFormats/Bgra5551.cs | 5 +- src/ImageSharp/PixelFormats/Byte4.cs | 5 +- src/ImageSharp/PixelFormats/HalfSingle.cs | 5 +- src/ImageSharp/PixelFormats/HalfVector2.cs | 5 +- src/ImageSharp/PixelFormats/HalfVector4.cs | 5 +- src/ImageSharp/PixelFormats/IPixel.cs | 18 +++- .../PixelFormats/NormalizedByte2.cs | 5 +- .../PixelFormats/NormalizedByte4.cs | 5 +- .../PixelFormats/NormalizedShort2.cs | 5 +- .../PixelFormats/NormalizedShort4.cs | 5 +- .../PixelFormats/PixelBlender{TPixel}.cs | 84 +++++++++---------- src/ImageSharp/PixelFormats/Rg32.cs | 5 +- src/ImageSharp/PixelFormats/Rgba1010102.cs | 5 +- src/ImageSharp/PixelFormats/RgbaVector.cs | 5 +- src/ImageSharp/PixelFormats/Short2.cs | 5 +- src/ImageSharp/PixelFormats/Short4.cs | 5 +- 22 files changed, 148 insertions(+), 64 deletions(-) diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/Alpha8.cs index 1e724768d0..730734f5f8 100644 --- a/src/ImageSharp/PixelFormats/Alpha8.cs +++ b/src/ImageSharp/PixelFormats/Alpha8.cs @@ -105,7 +105,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(0, 0, 0, this.PackedValue); + public void ToRgba32(ref Rgba32 dest) + { + dest = default; + dest.A = this.PackedValue; + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Argb32.cs b/src/ImageSharp/PixelFormats/Argb32.cs index 1e3bd93262..a47d7e8e78 100644 --- a/src/ImageSharp/PixelFormats/Argb32.cs +++ b/src/ImageSharp/PixelFormats/Argb32.cs @@ -250,7 +250,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A); + public void ToRgba32(ref Rgba32 dest) + { + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + dest.A = this.A; + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Bgr24.cs b/src/ImageSharp/PixelFormats/Bgr24.cs index ed65bebf7f..8eba08bea5 100644 --- a/src/ImageSharp/PixelFormats/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/Bgr24.cs @@ -151,7 +151,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, byte.MaxValue); + public void ToRgba32(ref Rgba32 dest) + { + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + dest.A = byte.MaxValue; + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Bgr565.cs b/src/ImageSharp/PixelFormats/Bgr565.cs index 04af6ef0f1..295f1ca0a0 100644 --- a/src/ImageSharp/PixelFormats/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/Bgr565.cs @@ -113,7 +113,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Bgra32.cs b/src/ImageSharp/PixelFormats/Bgra32.cs index 9b0ed4f96d..5d70c9e50b 100644 --- a/src/ImageSharp/PixelFormats/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/Bgra32.cs @@ -206,7 +206,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A); + public void ToRgba32(ref Rgba32 dest) + { + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + dest.A = this.A; + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Bgra4444.cs b/src/ImageSharp/PixelFormats/Bgra4444.cs index db1c8f865a..29ea63e20f 100644 --- a/src/ImageSharp/PixelFormats/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/Bgra4444.cs @@ -116,7 +116,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Bgra5551.cs b/src/ImageSharp/PixelFormats/Bgra5551.cs index 5d9003cdd3..f6dbb7811a 100644 --- a/src/ImageSharp/PixelFormats/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/Bgra5551.cs @@ -117,7 +117,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Byte4.cs b/src/ImageSharp/PixelFormats/Byte4.cs index 230c31c5c3..96eeeec0d4 100644 --- a/src/ImageSharp/PixelFormats/Byte4.cs +++ b/src/ImageSharp/PixelFormats/Byte4.cs @@ -117,7 +117,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/HalfSingle.cs b/src/ImageSharp/PixelFormats/HalfSingle.cs index bef4a5dd9b..a1811e147e 100644 --- a/src/ImageSharp/PixelFormats/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/HalfSingle.cs @@ -106,7 +106,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/HalfVector2.cs b/src/ImageSharp/PixelFormats/HalfVector2.cs index 5bd9924c53..381650aec5 100644 --- a/src/ImageSharp/PixelFormats/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/HalfVector2.cs @@ -117,7 +117,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/HalfVector4.cs b/src/ImageSharp/PixelFormats/HalfVector4.cs index 2e487ef985..b7d6687eab 100644 --- a/src/ImageSharp/PixelFormats/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/HalfVector4.cs @@ -125,7 +125,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index 87125fa0a3..c0bcfa459d 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -100,8 +100,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Expands the packed representation into an . /// - /// The . - Rgba32 ToRgba32(); + /// The reference to the destination pixel + void ToRgba32(ref Rgba32 dest); /// /// Packs the pixel from an value. @@ -115,4 +115,18 @@ namespace SixLabors.ImageSharp.PixelFormats /// The value. void PackFromRgba64(Rgba64 source); } + + /// + /// Temporary extension methods for compatibility + /// + internal static class PixelExtensions + { + public static Rgba32 ToRgba32(this TPixel pixel) + where TPixel : struct, IPixel + { + Rgba32 result = default; + pixel.ToRgba32(ref result); + return result; + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/NormalizedByte2.cs index 219ec87630..9999cfe03b 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte2.cs @@ -107,7 +107,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/NormalizedByte4.cs index d5795cb4bd..5f9124bdce 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte4.cs @@ -128,7 +128,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/NormalizedShort2.cs index 34e752496a..0cd8d9408f 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort2.cs @@ -123,7 +123,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/NormalizedShort4.cs index 6fda84bc2e..21aac4d248 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort4.cs @@ -130,7 +130,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs index 63a101656e..cca4a10179 100644 --- a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs @@ -1,31 +1,31 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; +// Copyright (c) Six Labors and contributors. +// 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 -{ - /// - /// Abstract base class for calling pixel composition functions - /// - /// The type of the pixel - internal abstract class PixelBlender - where TPixel : struct, IPixel - { - /// - /// Blend 2 pixels together. - /// - /// The background color. - /// The source color. - /// - /// 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. - /// - /// The final pixel value after composition +using SixLabors.Memory; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Abstract base class for calling pixel composition functions + /// + /// The type of the pixel + internal abstract class PixelBlender + where TPixel : struct, IPixel + { + /// + /// Blend 2 pixels together. + /// + /// The background color. + /// The source color. + /// + /// 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. + /// + /// The final pixel value after composition public abstract TPixel Blend(TPixel background, TPixel source, float amount); /// @@ -34,9 +34,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// 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. + /// + /// 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. /// protected abstract void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount); @@ -46,9 +46,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// 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. + /// + /// 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); @@ -59,9 +59,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// 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. + /// + /// 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) { @@ -76,9 +76,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// 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. + /// + /// 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 @@ -110,9 +110,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// 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. + /// + /// 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 @@ -135,5 +135,5 @@ namespace SixLabors.ImageSharp.PixelFormats PixelOperations.Instance.PackFromScaledVector4(destinationSpan, destination, destination.Length); } } - } -} + } +} diff --git a/src/ImageSharp/PixelFormats/Rg32.cs b/src/ImageSharp/PixelFormats/Rg32.cs index 0831f6524e..878b2342f9 100644 --- a/src/ImageSharp/PixelFormats/Rg32.cs +++ b/src/ImageSharp/PixelFormats/Rg32.cs @@ -111,7 +111,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Rgba1010102.cs b/src/ImageSharp/PixelFormats/Rgba1010102.cs index 14265b54e9..7f3e3a8706 100644 --- a/src/ImageSharp/PixelFormats/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/Rgba1010102.cs @@ -117,7 +117,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/RgbaVector.cs b/src/ImageSharp/PixelFormats/RgbaVector.cs index b2a3dc578e..25b8155d31 100644 --- a/src/ImageSharp/PixelFormats/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/RgbaVector.cs @@ -152,7 +152,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Short2.cs b/src/ImageSharp/PixelFormats/Short2.cs index 81df3ef7b9..69a4e35e93 100644 --- a/src/ImageSharp/PixelFormats/Short2.cs +++ b/src/ImageSharp/PixelFormats/Short2.cs @@ -129,7 +129,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Short4.cs b/src/ImageSharp/PixelFormats/Short4.cs index 48bd01d6e1..653bc030f8 100644 --- a/src/ImageSharp/PixelFormats/Short4.cs +++ b/src/ImageSharp/PixelFormats/Short4.cs @@ -134,7 +134,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] From ee1ad0c01e75756a156348ed3d099422fd319e59 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 01:58:12 +0200 Subject: [PATCH 191/381] refactor ToRgba32() on the rest --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 2 +- src/ImageSharp/PixelFormats/Gray16.cs | 7 +++++-- src/ImageSharp/PixelFormats/Gray8.cs | 8 +++++++- src/ImageSharp/PixelFormats/Rgb24.cs | 8 +++++++- src/ImageSharp/PixelFormats/Rgb48.cs | 10 +++++----- src/ImageSharp/PixelFormats/Rgba32.cs | 5 ++++- src/ImageSharp/PixelFormats/Rgba64.cs | 11 +++++------ 7 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 1dc7405677..6c52eded5f 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp /// /// Scales a value from a 16 bit to it's 8 bit equivalent. /// - /// The 8 bit compoonent value. + /// The 8 bit component value. /// The [MethodImpl(InliningOptions.ShortMethod)] public static byte DownScaleFrom16BitTo8Bit(ushort component) diff --git a/src/ImageSharp/PixelFormats/Gray16.cs b/src/ImageSharp/PixelFormats/Gray16.cs index 34f221d79c..788278be4e 100644 --- a/src/ImageSharp/PixelFormats/Gray16.cs +++ b/src/ImageSharp/PixelFormats/Gray16.cs @@ -136,10 +136,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() + public void ToRgba32(ref Rgba32 dest) { byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(this.PackedValue); - return new Rgba32(rgb, rgb, rgb, byte.MaxValue); + dest.R = rgb; + dest.G = rgb; + dest.B = rgb; + dest.A = byte.MaxValue; } /// diff --git a/src/ImageSharp/PixelFormats/Gray8.cs b/src/ImageSharp/PixelFormats/Gray8.cs index 5812405876..8a9ec540dc 100644 --- a/src/ImageSharp/PixelFormats/Gray8.cs +++ b/src/ImageSharp/PixelFormats/Gray8.cs @@ -108,7 +108,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.PackedValue, this.PackedValue, this.PackedValue, byte.MaxValue); + public void ToRgba32(ref Rgba32 dest) + { + dest.R = this.PackedValue; + dest.G = this.PackedValue; + dest.B = this.PackedValue; + dest.A = byte.MaxValue; + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Rgb24.cs b/src/ImageSharp/PixelFormats/Rgb24.cs index a2b896605d..0113027d62 100644 --- a/src/ImageSharp/PixelFormats/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/Rgb24.cs @@ -165,7 +165,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, byte.MaxValue); + public void ToRgba32(ref Rgba32 dest) + { + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + dest.A = byte.MaxValue; + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Rgb48.cs b/src/ImageSharp/PixelFormats/Rgb48.cs index 7406fda429..815bf8c913 100644 --- a/src/ImageSharp/PixelFormats/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/Rgb48.cs @@ -165,12 +165,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() + public void ToRgba32(ref Rgba32 dest) { - byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R); - byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G); - byte b = ImageMaths.DownScaleFrom16BitTo8Bit(this.B); - return new Rgba32(r, g, b, byte.MaxValue); + dest.R = ImageMaths.DownScaleFrom16BitTo8Bit(this.R); + dest.G = ImageMaths.DownScaleFrom16BitTo8Bit(this.G); + dest.B = ImageMaths.DownScaleFrom16BitTo8Bit(this.B); + dest.A = byte.MaxValue; } /// diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index 415c39c0ed..e866d1350a 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -301,7 +301,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => this; + public void ToRgba32(ref Rgba32 dest) + { + dest = this; + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/Rgba64.cs index 738c5e3dd8..2d1a676705 100644 --- a/src/ImageSharp/PixelFormats/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/Rgba64.cs @@ -197,13 +197,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() + public void ToRgba32(ref Rgba32 dest) { - byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R); - byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G); - byte b = ImageMaths.DownScaleFrom16BitTo8Bit(this.B); - byte a = ImageMaths.DownScaleFrom16BitTo8Bit(this.A); - return new Rgba32(r, g, b, a); + dest.R = ImageMaths.DownScaleFrom16BitTo8Bit(this.R); + dest.G = ImageMaths.DownScaleFrom16BitTo8Bit(this.G); + dest.B = ImageMaths.DownScaleFrom16BitTo8Bit(this.B); + dest.A = ImageMaths.DownScaleFrom16BitTo8Bit(this.A); } /// From 45c5e87fa4f3314cdd6583bb62105fc393907d7f Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 02:15:15 +0200 Subject: [PATCH 192/381] drop all PixelExtensions usages in product code, keep in test code for now. --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 7 ++++-- src/ImageSharp/PixelFormats/IPixel.cs | 14 ------------ .../PixelFormats/PixelExtensions.cs | 22 +++++++++++++++++++ .../BinaryErrorDiffusionProcessor.cs | 5 +++-- .../BinaryOrderedDitherProcessor.cs | 5 +++-- .../Binarization/BinaryThresholdProcessor.cs | 3 ++- .../ErrorDiffusionPaletteProcessor.cs | 5 +++-- .../OrderedDitherPaletteProcessor.cs | 5 +++-- .../OctreeFrameQuantizer{TPixel}.cs | 12 ++++++---- .../Quantization/WuFrameQuantizer{TPixel}.cs | 3 ++- .../Color/Bulk/ToXyzw.cs | 3 ++- .../Transforms/AffineTransformTests.cs | 3 ++- 12 files changed, 55 insertions(+), 32 deletions(-) create mode 100644 src/ImageSharp/PixelFormats/PixelExtensions.cs diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 1e9dbc71a1..cf7b7b2c66 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -386,9 +386,10 @@ namespace SixLabors.ImageSharp.Formats.Png { // 8 bit grayscale + alpha // TODO: Should we consider in the future a GrayAlpha16 type. + Rgba32 rgba = default; for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 2) { - var rgba = Unsafe.Add(ref rowSpanRef, x).ToRgba32(); + Unsafe.Add(ref rowSpanRef, x).ToRgba32(ref rgba); Unsafe.Add(ref rawScanlineSpanRef, o) = ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); Unsafe.Add(ref rawScanlineSpanRef, o + 1) = rgba.A; } @@ -645,12 +646,14 @@ namespace SixLabors.ImageSharp.Formats.Png ref byte alphaTableRef = ref MemoryMarshal.GetReference(alphaTable.GetSpan()); Span quantizedSpan = quantized.GetPixelSpan(); + Rgba32 rgba = default; + for (int i = 0; i < paletteLength; i++) { if (quantizedSpan.IndexOf((byte)i) > -1) { int offset = i * 3; - var rgba = palette[i].ToRgba32(); + palette[i].ToRgba32(ref rgba); byte alpha = rgba.A; diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index c0bcfa459d..3a6fb0a78c 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -115,18 +115,4 @@ namespace SixLabors.ImageSharp.PixelFormats /// The value. void PackFromRgba64(Rgba64 source); } - - /// - /// Temporary extension methods for compatibility - /// - internal static class PixelExtensions - { - public static Rgba32 ToRgba32(this TPixel pixel) - where TPixel : struct, IPixel - { - Rgba32 result = default; - pixel.ToRgba32(ref result); - return result; - } - } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelExtensions.cs b/src/ImageSharp/PixelFormats/PixelExtensions.cs new file mode 100644 index 0000000000..175696ab63 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelExtensions.cs @@ -0,0 +1,22 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Low-performance extension methods to help conversion syntax, suitable for testing purposes. + /// + internal static class PixelExtensions + { + /// + /// Returns the result of as a new instance. + /// + public static Rgba32 ToRgba32(this TPixel pixel) + where TPixel : struct, IPixel + { + Rgba32 result = default; + pixel.ToRgba32(ref result); + return result; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs index b338ff446e..32cc2f434b 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs @@ -88,7 +88,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // Collect the values before looping so we can reduce our calculation count for identical sibling pixels TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; - var rgba = sourcePixel.ToRgba32(); + Rgba32 rgba = default; + sourcePixel.ToRgba32(ref rgba); // Convert to grayscale using ITU-R Recommendation BT.709 if required byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); @@ -105,7 +106,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // rather than calculating it again. This is an inexpensive optimization. if (!previousPixel.Equals(sourcePixel)) { - rgba = sourcePixel.ToRgba32(); + sourcePixel.ToRgba32(ref rgba); luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs index 0b28a1574b..cfdaf107c3 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs @@ -67,7 +67,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // Collect the values before looping so we can reduce our calculation count for identical sibling pixels TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; - var rgba = sourcePixel.ToRgba32(); + Rgba32 rgba = default; + sourcePixel.ToRgba32(ref rgba); // Convert to grayscale using ITU-R Recommendation BT.709 if required byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); @@ -84,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // rather than calculating it again. This is an inexpensive optimization. if (!previousPixel.Equals(sourcePixel)) { - rgba = sourcePixel.ToRgba32(); + sourcePixel.ToRgba32(ref rgba); luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs index 03b7f73e94..67dcfc7f1b 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs @@ -80,6 +80,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization configuration, rows => { + Rgba32 rgba = default; for (int y = rows.Min; y < rows.Max; y++) { Span row = source.GetPixelRowSpan(y); @@ -87,7 +88,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization for (int x = startX; x < endX; x++) { ref TPixel color = ref row[x]; - var rgba = color.ToRgba32(); + color.ToRgba32(ref rgba); // Convert to grayscale using ITU-R Recommendation BT.709 if required byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs index b60322799a..911d3e8fdc 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs @@ -76,7 +76,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; PixelPair pair = this.GetClosestPixelPair(ref sourcePixel); - var rgba = sourcePixel.ToRgba32(); + Rgba32 rgba = default; + sourcePixel.ToRgba32(ref rgba); // Convert to grayscale using ITU-R Recommendation BT.709 if required byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); @@ -101,7 +102,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering continue; } - rgba = sourcePixel.ToRgba32(); + sourcePixel.ToRgba32(ref rgba); luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs index 149c7170ac..1b4910a147 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs @@ -53,7 +53,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; PixelPair pair = this.GetClosestPixelPair(ref sourcePixel); - var rgba = sourcePixel.ToRgba32(); + Rgba32 rgba = default; + sourcePixel.ToRgba32(ref rgba); // Convert to grayscale using ITU-R Recommendation BT.709 if required byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); @@ -78,7 +79,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering continue; } - rgba = sourcePixel.ToRgba32(); + sourcePixel.ToRgba32(ref rgba); luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs index 552aa8af82..29742725a0 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs @@ -154,7 +154,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization return this.GetClosestPixel(ref pixel); } - var rgba = pixel.ToRgba32(); + Rgba32 rgba = default; + pixel.ToRgba32(ref rgba); if (rgba.Equals(default)) { return this.transparentIndex; @@ -434,7 +435,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { // Go to the next level down in the tree int shift = 7 - level; - var rgba = pixel.ToRgba32(); + Rgba32 rgba = default; + pixel.ToRgba32(ref rgba); int index = ((rgba.B & Mask[level]) >> (shift - 2)) | ((rgba.G & Mask[level]) >> (shift - 1)) @@ -529,7 +531,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (!this.leaf) { int shift = 7 - level; - var rgba = pixel.ToRgba32(); + Rgba32 rgba = default; + pixel.ToRgba32(ref rgba); int pixelIndex = ((rgba.B & Mask[level]) >> (shift - 2)) | ((rgba.G & Mask[level]) >> (shift - 1)) @@ -556,7 +559,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Increment(ref TPixel pixel) { - var rgba = pixel.ToRgba32(); + Rgba32 rgba = default; + pixel.ToRgba32(ref rgba); this.pixelCount++; this.red += rgba.R; this.green += rgba.G; diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index f3b5da3202..4ef1659605 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -879,7 +879,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } // Expected order r->g->b->a - var rgba = pixel.ToRgba32(); + Rgba32 rgba = default; + pixel.ToRgba32(ref rgba); int r = rgba.R >> (8 - IndexBits); int g = rgba.G >> (8 - IndexBits); diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs index 740287e85a..0cf7087d4c 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs @@ -46,7 +46,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk { TPixel c = s[i]; int i4 = i * 4; - var rgba = c.ToRgba32(); + Rgba32 rgba = default; + c.ToRgba32(ref rgba); d[i4] = rgba.R; d[i4 + 1] = rgba.G; d[i4 + 2] = rgba.B; diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index 17240839db..ae572498a4 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -240,7 +240,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms var white = new Rgb24(255, 255, 255); foreach (TPixel pixel in data) { - var rgba = pixel.ToRgba32(); + Rgba32 rgba = default; + pixel.ToRgba32(ref rgba); if (rgba.A == 0) { continue; From 5a070ea6d67457dfc11114adf6548a5c6a9f0770 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 02:18:28 +0200 Subject: [PATCH 193/381] wakeup message to the git status-checks --- tests/ImageSharp.Tests/Numerics/RationalTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Numerics/RationalTests.cs b/tests/ImageSharp.Tests/Numerics/RationalTests.cs index a9b9106c5c..caddd49216 100644 --- a/tests/ImageSharp.Tests/Numerics/RationalTests.cs +++ b/tests/ImageSharp.Tests/Numerics/RationalTests.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.Primitives; using Xunit; From 6ca596d3554974eeb37cfcb13fb8929f6050ced4 Mon Sep 17 00:00:00 2001 From: Anton Firsov Date: Mon, 22 Oct 2018 02:25:15 +0200 Subject: [PATCH 194/381] Something's wrong with the status checks --- tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs b/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs index f092da7082..950434ac32 100644 --- a/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs +++ b/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs @@ -2,7 +2,6 @@ using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Memory; -using SixLabors.Memory; using Xunit; @@ -35,4 +34,4 @@ namespace SixLabors.ImageSharp.Tests.Helpers } } } -} \ No newline at end of file +} From ea5658a72a44c59fc14ee3dd09cb3d92d0b39c95 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 12:46:16 +0200 Subject: [PATCH 195/381] fix typo --- src/ImageSharp/Common/Helpers/SimdUtils.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index 737e620061..71eb88b1d1 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp // Deal with the remainder: if (source.Length > 0) { - ConverByteToNormalizedFloatRemainder(source, dest); + ConvertByteToNormalizedFloatRemainder(source, dest); } } @@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp } [MethodImpl(InliningOptions.ColdPath)] - private static void ConverByteToNormalizedFloatRemainder(ReadOnlySpan source, Span dest) + private static void ConvertByteToNormalizedFloatRemainder(ReadOnlySpan source, Span dest) { ref byte sBase = ref MemoryMarshal.GetReference(source); ref float dBase = ref MemoryMarshal.GetReference(dest); From 9bc99a6d78adfbffb1f3aab8c7e7161d58c3f5e3 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 13:00:08 +0200 Subject: [PATCH 196/381] Move all specific IPixel implementations to a (non-namespace-provider) subfolder --- src/ImageSharp/ImageSharp.csproj | 40 +++++++++---------- src/ImageSharp/ImageSharp.csproj.DotSettings | 7 +++- src/ImageSharp/PixelFormats/ComponentOrder.cs | 31 -------------- .../{ => PixelImplementations}/Alpha8.cs | 0 .../{ => PixelImplementations}/Argb32.cs | 0 .../{ => PixelImplementations}/Bgr24.cs | 0 .../{ => PixelImplementations}/Bgr565.cs | 0 .../{ => PixelImplementations}/Bgra32.cs | 0 .../{ => PixelImplementations}/Bgra4444.cs | 0 .../{ => PixelImplementations}/Bgra5551.cs | 0 .../{ => PixelImplementations}/Byte4.cs | 0 .../Argb32.PixelOperations.Generated.cs | 0 .../Argb32.PixelOperations.Generated.tt | 0 .../Bgr24.PixelOperations.Generated.cs | 0 .../Bgr24.PixelOperations.Generated.tt | 0 .../Bgra32.PixelOperations.Generated.cs | 0 .../Bgra32.PixelOperations.Generated.tt | 0 .../Gray16.PixelOperations.Generated.cs | 0 .../Gray16.PixelOperations.Generated.tt | 0 .../Gray8.PixelOperations.Generated.cs | 0 .../Gray8.PixelOperations.Generated.tt | 0 .../Rgb24.PixelOperations.Generated.cs | 0 .../Rgb24.PixelOperations.Generated.tt | 0 .../Rgb48.PixelOperations.Generated.cs | 0 .../Rgb48.PixelOperations.Generated.tt | 0 .../Rgba32.PixelOperations.Generated.cs | 0 .../Rgba32.PixelOperations.Generated.tt | 0 .../Rgba64.PixelOperations.Generated.cs | 0 .../Rgba64.PixelOperations.Generated.tt | 0 .../{ => PixelImplementations}/Gray16.cs | 0 .../{ => PixelImplementations}/Gray8.cs | 0 .../{ => PixelImplementations}/HalfSingle.cs | 0 .../{ => PixelImplementations}/HalfVector2.cs | 0 .../{ => PixelImplementations}/HalfVector4.cs | 0 .../NormalizedByte2.cs | 0 .../NormalizedByte4.cs | 0 .../NormalizedShort2.cs | 0 .../NormalizedShort4.cs | 0 .../{ => PixelImplementations}/Rg32.cs | 0 .../{ => PixelImplementations}/Rgb24.cs | 0 .../{ => PixelImplementations}/Rgb48.cs | 0 .../{ => PixelImplementations}/Rgba1010102.cs | 0 .../Rgba32.Definitions.cs | 0 .../Rgba32.PixelOperations.cs | 0 .../{ => PixelImplementations}/Rgba32.cs | 0 .../{ => PixelImplementations}/Rgba64.cs | 0 .../RgbaVector.PixelOperations.cs | 0 .../{ => PixelImplementations}/RgbaVector.cs | 0 .../{ => PixelImplementations}/Short2.cs | 0 .../{ => PixelImplementations}/Short4.cs | 0 .../PixelOperations{TPixel}.Generated.cs | 0 .../PixelOperations{TPixel}.Generated.tt | 0 52 files changed, 26 insertions(+), 52 deletions(-) delete mode 100644 src/ImageSharp/PixelFormats/ComponentOrder.cs rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Alpha8.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Argb32.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Bgr24.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Bgr565.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Bgra32.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Bgra4444.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Bgra5551.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Byte4.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Argb32.PixelOperations.Generated.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Argb32.PixelOperations.Generated.tt (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Bgr24.PixelOperations.Generated.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Bgr24.PixelOperations.Generated.tt (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Bgra32.PixelOperations.Generated.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Bgra32.PixelOperations.Generated.tt (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Gray16.PixelOperations.Generated.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Gray16.PixelOperations.Generated.tt (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Gray8.PixelOperations.Generated.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Gray8.PixelOperations.Generated.tt (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Rgb24.PixelOperations.Generated.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Rgb24.PixelOperations.Generated.tt (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Rgb48.PixelOperations.Generated.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Rgb48.PixelOperations.Generated.tt (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Rgba32.PixelOperations.Generated.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Rgba32.PixelOperations.Generated.tt (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Rgba64.PixelOperations.Generated.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Rgba64.PixelOperations.Generated.tt (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Gray16.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Gray8.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/HalfSingle.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/HalfVector2.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/HalfVector4.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/NormalizedByte2.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/NormalizedByte4.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/NormalizedShort2.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/NormalizedShort4.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Rg32.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Rgb24.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Rgb48.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Rgba1010102.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Rgba32.Definitions.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Rgba32.PixelOperations.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Rgba32.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Rgba64.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/RgbaVector.PixelOperations.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/RgbaVector.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Short2.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Short4.cs (100%) rename src/ImageSharp/PixelFormats/{Generated => }/PixelOperations{TPixel}.Generated.cs (100%) rename src/ImageSharp/PixelFormats/{Generated => }/PixelOperations{TPixel}.Generated.tt (100%) diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 17e417dca8..8d2ad2abe3 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -72,43 +72,43 @@ TextTemplatingFileGenerator Block8x8F.Generated.cs - + TextTemplatingFileGenerator PixelOperations{TPixel}.Generated.cs - + TextTemplatingFileGenerator Argb32.PixelOperations.Generated.cs - + TextTemplatingFileGenerator Bgr24.PixelOperations.Generated.cs - + TextTemplatingFileGenerator Bgra32.PixelOperations.Generated.cs - + TextTemplatingFileGenerator Gray8.PixelOperations.Generated.cs - + TextTemplatingFileGenerator Gray16.PixelOperations.Generated.cs - + TextTemplatingFileGenerator Rgb24.PixelOperations.Generated.cs - + TextTemplatingFileGenerator Rgba32.PixelOperations.Generated.cs - + TextTemplatingFileGenerator Rgb48.PixelOperations.Generated.cs - + TextTemplatingFileGenerator Rgba64.PixelOperations.Generated.cs @@ -137,52 +137,52 @@ True Block8x8F.Generated.tt - + True True PixelOperations{TPixel}.Generated.tt - + True True Argb32.PixelOperations.Generated.tt - + True True Bgr24.PixelOperations.Generated.tt - + True True Bgra32.PixelOperations.Generated.tt - + True True Gray8.PixelOperations.Generated.tt - + True True Gray16.PixelOperations.Generated.tt - + True True Rgb24.PixelOperations.Generated.tt - + True True Rgba32.PixelOperations.Generated.tt - + True True Rgb48.PixelOperations.Generated.tt - + True True Rgba64.PixelOperations.Generated.tt diff --git a/src/ImageSharp/ImageSharp.csproj.DotSettings b/src/ImageSharp/ImageSharp.csproj.DotSettings index 8b2e1bcf07..cd75f91b7b 100644 --- a/src/ImageSharp/ImageSharp.csproj.DotSettings +++ b/src/ImageSharp/ImageSharp.csproj.DotSettings @@ -1,3 +1,8 @@  True - True \ No newline at end of file + True + True + True + True + True + True \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/ComponentOrder.cs b/src/ImageSharp/PixelFormats/ComponentOrder.cs deleted file mode 100644 index 868d082599..0000000000 --- a/src/ImageSharp/PixelFormats/ComponentOrder.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Enumerates the various component orders. - /// - internal enum ComponentOrder - { - /// - /// Z-> Y-> X order. Equivalent to B-> G-> R in - /// - Zyx, - - /// - /// Z-> Y-> X-> W order. Equivalent to B-> G-> R-> A in - /// - Zyxw, - - /// - /// X-> Y-> Z order. Equivalent to R-> G-> B in - /// - Xyz, - - /// - /// X-> Y-> Z-> W order. Equivalent to R-> G-> B-> A in - /// - Xyzw, - } -} diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Alpha8.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Alpha8.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Alpha8.cs diff --git a/src/ImageSharp/PixelFormats/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Argb32.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs diff --git a/src/ImageSharp/PixelFormats/Bgr24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Bgr24.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs diff --git a/src/ImageSharp/PixelFormats/Bgr565.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Bgr565.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs diff --git a/src/ImageSharp/PixelFormats/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Bgra32.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs diff --git a/src/ImageSharp/PixelFormats/Bgra4444.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Bgra4444.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs diff --git a/src/ImageSharp/PixelFormats/Bgra5551.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Bgra5551.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs diff --git a/src/ImageSharp/PixelFormats/Byte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Byte4.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs diff --git a/src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs diff --git a/src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.tt rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt diff --git a/src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs diff --git a/src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.tt rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt diff --git a/src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs diff --git a/src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.tt rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt diff --git a/src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs diff --git a/src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.tt rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt diff --git a/src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs diff --git a/src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.tt rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt diff --git a/src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs diff --git a/src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.tt rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt diff --git a/src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs diff --git a/src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.tt rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.tt rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt diff --git a/src/ImageSharp/PixelFormats/Gray16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Gray16.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Gray16.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Gray16.cs diff --git a/src/ImageSharp/PixelFormats/Gray8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Gray8.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs diff --git a/src/ImageSharp/PixelFormats/HalfSingle.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs similarity index 100% rename from src/ImageSharp/PixelFormats/HalfSingle.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs diff --git a/src/ImageSharp/PixelFormats/HalfVector2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs similarity index 100% rename from src/ImageSharp/PixelFormats/HalfVector2.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs diff --git a/src/ImageSharp/PixelFormats/HalfVector4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs similarity index 100% rename from src/ImageSharp/PixelFormats/HalfVector4.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs diff --git a/src/ImageSharp/PixelFormats/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs similarity index 100% rename from src/ImageSharp/PixelFormats/NormalizedByte2.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs diff --git a/src/ImageSharp/PixelFormats/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs similarity index 100% rename from src/ImageSharp/PixelFormats/NormalizedByte4.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs diff --git a/src/ImageSharp/PixelFormats/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs similarity index 100% rename from src/ImageSharp/PixelFormats/NormalizedShort2.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs diff --git a/src/ImageSharp/PixelFormats/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs similarity index 100% rename from src/ImageSharp/PixelFormats/NormalizedShort4.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs diff --git a/src/ImageSharp/PixelFormats/Rg32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Rg32.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs diff --git a/src/ImageSharp/PixelFormats/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Rgb24.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs diff --git a/src/ImageSharp/PixelFormats/Rgb48.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Rgb48.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs diff --git a/src/ImageSharp/PixelFormats/Rgba1010102.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Rgba1010102.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs diff --git a/src/ImageSharp/PixelFormats/Rgba32.Definitions.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.Definitions.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Rgba32.Definitions.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.Definitions.cs diff --git a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Rgba32.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Rgba64.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs diff --git a/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs similarity index 100% rename from src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs diff --git a/src/ImageSharp/PixelFormats/RgbaVector.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs similarity index 100% rename from src/ImageSharp/PixelFormats/RgbaVector.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs diff --git a/src/ImageSharp/PixelFormats/Short2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Short2.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs diff --git a/src/ImageSharp/PixelFormats/Short4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Short4.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs rename to src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt rename to src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt From d4be172dcc44f19136e286cce5b855985a58ffba Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 13:39:10 +0200 Subject: [PATCH 197/381] simplify IPixel method names: PackFrom*** -> From*** --- .../Processing/GradientBrushBase{TPixel}.cs | 2 +- .../Processing/RecolorBrush{TPixel}.cs | 4 +- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 6 +- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 4 +- .../Formats/Png/PngScanlineProcessor.cs | 52 ++--- .../PixelFormats/ColorBuilder{TPixel}.cs | 4 +- src/ImageSharp/PixelFormats/IPixel.cs | 22 +- .../DefaultPixelBlenders.Generated.cs | 216 +++++++++--------- .../PorterDuffFunctions.Generated.cs | 216 +++++++++--------- .../PixelImplementations/Alpha8.cs | 22 +- .../PixelImplementations/Argb32.cs | 22 +- .../PixelImplementations/Bgr24.cs | 26 +-- .../PixelImplementations/Bgr565.cs | 24 +- .../PixelImplementations/Bgra32.cs | 22 +- .../PixelImplementations/Bgra4444.cs | 24 +- .../PixelImplementations/Bgra5551.cs | 24 +- .../PixelImplementations/Byte4.cs | 24 +- .../Argb32.PixelOperations.Generated.cs | 16 +- .../Bgr24.PixelOperations.Generated.cs | 16 +- .../Bgra32.PixelOperations.Generated.cs | 16 +- .../Gray16.PixelOperations.Generated.cs | 16 +- .../Gray8.PixelOperations.Generated.cs | 16 +- .../Rgb24.PixelOperations.Generated.cs | 16 +- .../Rgb48.PixelOperations.Generated.cs | 16 +- .../Rgba32.PixelOperations.Generated.cs | 16 +- .../Rgba64.PixelOperations.Generated.cs | 16 +- .../PixelImplementations/Gray16.cs | 22 +- .../PixelImplementations/Gray8.cs | 22 +- .../PixelImplementations/HalfSingle.cs | 24 +- .../PixelImplementations/HalfVector2.cs | 24 +- .../PixelImplementations/HalfVector4.cs | 26 +-- .../PixelImplementations/NormalizedByte2.cs | 24 +- .../PixelImplementations/NormalizedByte4.cs | 26 +-- .../PixelImplementations/NormalizedShort2.cs | 24 +- .../PixelImplementations/NormalizedShort4.cs | 26 +-- .../PixelFormats/PixelImplementations/Rg32.cs | 24 +- .../PixelImplementations/Rgb24.cs | 24 +- .../PixelImplementations/Rgb48.cs | 22 +- .../PixelImplementations/Rgba1010102.cs | 24 +- .../PixelImplementations/Rgba32.cs | 24 +- .../PixelImplementations/Rgba64.cs | 22 +- .../PixelImplementations/RgbaVector.cs | 24 +- .../PixelImplementations/Short2.cs | 24 +- .../PixelImplementations/Short4.cs | 26 +-- .../PixelOperations{TPixel}.Generated.cs | 36 +-- .../PixelFormats/PixelOperations{TPixel}.cs | 10 +- .../EdgeDetectorCompassProcessor.cs | 2 +- .../Processors/Dithering/ErrorDiffuserBase.cs | 2 +- .../Effects/OilPaintingProcessor.cs | 2 +- .../Processors/Filters/FilterProcessor.cs | 2 +- .../HistogramEqualizationProcessor.cs | 2 +- .../OctreeFrameQuantizer{TPixel}.cs | 2 +- .../Quantization/WuFrameQuantizer{TPixel}.cs | 2 +- .../Transforms/AffineTransformProcessor.cs | 2 +- .../ProjectiveTransformProcessor.cs | 2 +- .../Color/Bulk/PackFromVector4.cs | 2 +- .../Color/Bulk/PackFromXyzw.cs | 2 +- tests/ImageSharp.Benchmarks/Samplers/Glow.cs | 2 +- .../Drawing/FillSolidBrushTests.cs | 2 +- .../Drawing/SolidFillBlendedShapesTests.cs | 2 +- .../Formats/Jpg/GenericBlock8x8Tests.cs | 2 +- .../Jpg/Utils/LibJpegTools.ComponentData.cs | 2 +- .../Jpg/Utils/LibJpegTools.SpectralData.cs | 2 +- tests/ImageSharp.Tests/Issues/Issue594.cs | 8 +- .../PixelFormats/Alpha8Tests.cs | 2 +- .../PixelFormats/Argb32Tests.cs | 2 +- .../PixelFormats/Bgr24Tests.cs | 4 +- .../PixelFormats/Bgr565Tests.cs | 2 +- .../PixelFormats/Bgra32Tests.cs | 4 +- .../PixelFormats/Bgra4444Tests.cs | 2 +- .../PixelFormats/Bgra5551Tests.cs | 4 +- .../PixelFormats/Byte4Tests.cs | 2 +- .../PixelFormats/Gray16Tests.cs | 6 +- .../PixelFormats/Gray8Tests.cs | 6 +- .../PixelFormats/HalfSingleTests.cs | 2 +- .../PixelFormats/HalfVector2Tests.cs | 2 +- .../PixelFormats/HalfVector4Tests.cs | 2 +- .../PixelFormats/NormalizedByte2Tests.cs | 2 +- .../PixelFormats/NormalizedByte4Tests.cs | 2 +- .../PixelFormats/NormalizedShort2Tests.cs | 2 +- .../PixelFormats/NormalizedShort4Tests.cs | 2 +- .../PixelFormats/PixelOperationsTests.cs | 52 ++--- .../PixelFormats/Rg32Tests.cs | 2 +- .../PixelFormats/Rgb24Tests.cs | 4 +- .../PixelFormats/Rgb48Tests.cs | 2 +- .../PixelFormats/Rgba1010102Tests.cs | 2 +- .../PixelFormats/Rgba32Tests.cs | 24 +- .../PixelFormats/Rgba64Tests.cs | 6 +- .../PixelFormats/RgbaVectorTests.cs | 8 +- .../PixelFormats/Short2Tests.cs | 12 +- .../PixelFormats/Short4Tests.cs | 20 +- .../ImageProviders/SolidProvider.cs | 2 +- .../ImageProviders/TestPatternProvider.cs | 8 +- .../TestUtilities/ImagingTestCaseUtility.cs | 4 +- .../TestUtilities/TestImageExtensions.cs | 2 +- .../TestUtilities/TestPixel.cs | 2 +- .../Tests/TestUtilityExtensionsTests.cs | 2 +- 97 files changed, 789 insertions(+), 789 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/GradientBrushBase{TPixel}.cs b/src/ImageSharp.Drawing/Processing/GradientBrushBase{TPixel}.cs index 897b3f384f..00141a8d8d 100644 --- a/src/ImageSharp.Drawing/Processing/GradientBrushBase{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/GradientBrushBase{TPixel}.cs @@ -130,7 +130,7 @@ namespace SixLabors.ImageSharp.Processing onLocalGradient); TPixel resultColor = default; - resultColor.PackFromVector4(result); + resultColor.FromVector4(result); return resultColor; } } diff --git a/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs index 87e1dc146a..2968b68b55 100644 --- a/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs @@ -95,9 +95,9 @@ namespace SixLabors.ImageSharp.Processing // Lets hack a min max extremes for a color space by letting the IPackedPixel clamp our values to something in the correct spaces :) var maxColor = default(TPixel); - maxColor.PackFromVector4(new Vector4(float.MaxValue)); + maxColor.FromVector4(new Vector4(float.MaxValue)); var minColor = default(TPixel); - minColor.PackFromVector4(new Vector4(float.MinValue)); + minColor.FromVector4(new Vector4(float.MinValue)); this.threshold = Vector4.DistanceSquared(maxColor.ToVector4(), minColor.ToVector4()) * threshold; } diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index dabab651d0..8ebfb37ebd 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -231,7 +231,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp for (int x = 0; x < width; x++) { - color.PackFromBgr24(Unsafe.As(ref colors[bufferRow[x] * 4])); + color.FromBgr24(Unsafe.As(ref colors[bufferRow[x] * 4])); pixelRow[x] = color; } } @@ -365,7 +365,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp { int colorIndex = ((rowSpan[offset] >> (8 - bits - (shift * bits))) & mask) * 4; - color.PackFromBgr24(Unsafe.As(ref colors[colorIndex])); + color.FromBgr24(Unsafe.As(ref colors[colorIndex])); pixelRow[newX] = color; } @@ -408,7 +408,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp GetBytesFrom5BitValue((temp & Rgb16GMask) >> 5), GetBytesFrom5BitValue(temp & Rgb16BMask)); - color.PackFromRgb24(rgb); + color.FromRgb24(rgb); pixelRow[x] = color; offset += 2; } diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 155e6484f7..db512a0781 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -491,7 +491,7 @@ namespace SixLabors.ImageSharp.Formats.Gif int index = Unsafe.Add(ref indicesRef, i); ref TPixel pixel = ref Unsafe.Add(ref rowRef, x); Rgb24 rgb = colorTable[index]; - pixel.PackFromRgb24(rgb); + pixel.FromRgb24(rgb); i++; } @@ -506,7 +506,7 @@ namespace SixLabors.ImageSharp.Formats.Gif { ref TPixel pixel = ref Unsafe.Add(ref rowRef, x); Rgb24 rgb = colorTable[index]; - pixel.PackFromRgb24(rgb); + pixel.FromRgb24(rgb); } i++; diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index 70f2cb04b6..b4e5f201f0 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Formats.Png for (int x = 0, o = 0; x < header.Width; x++, o += 2) { ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - pixel.PackFromGray16(new Gray16(luminance)); + pixel.FromGray16(new Gray16(luminance)); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Formats.Png for (int x = 0; x < header.Width; x++) { byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * scaleFactor); - pixel.PackFromGray8(new Gray8(luminance)); + pixel.FromGray8(new Gray8(luminance)); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.B = luminance; rgba64.A = luminance.Equals(luminance16Trans) ? ushort.MinValue : ushort.MaxValue; - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba32.B = luminance; rgba32.A = luminance.Equals(scaledLuminanceTrans) ? byte.MinValue : byte.MaxValue; - pixel.PackFromRgba32(rgba32); + pixel.FromRgba32(rgba32); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.Formats.Png for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += 2) { ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - pixel.PackFromGray16(new Gray16(luminance)); + pixel.FromGray16(new Gray16(luminance)); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.Formats.Png for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++) { byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * scaleFactor); - pixel.PackFromGray8(new Gray8(luminance)); + pixel.FromGray8(new Gray8(luminance)); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -136,7 +136,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.B = luminance; rgba64.A = luminance.Equals(luminance16Trans) ? ushort.MinValue : ushort.MaxValue; - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -152,7 +152,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba32.B = luminance; rgba32.A = luminance.Equals(scaledLuminanceTrans) ? byte.MinValue : byte.MaxValue; - pixel.PackFromRgba32(rgba32); + pixel.FromRgba32(rgba32); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -182,7 +182,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.B = luminance; rgba64.A = alpha; - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -201,7 +201,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba32.B = luminance; rgba32.A = alpha; - pixel.PackFromRgba32(rgba32); + pixel.FromRgba32(rgba32); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -233,7 +233,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.B = luminance; rgba64.A = alpha; - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -250,7 +250,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba32.B = luminance; rgba32.A = alpha; - pixel.PackFromRgba32(rgba32); + pixel.FromRgba32(rgba32); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -283,7 +283,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); rgba.A = paletteAlpha.Length > index ? Unsafe.Add(ref paletteAlphaRef, index) : byte.MaxValue; - pixel.PackFromRgba32(rgba); + pixel.FromRgba32(rgba); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -294,7 +294,7 @@ namespace SixLabors.ImageSharp.Formats.Png int index = Unsafe.Add(ref scanlineSpanRef, x); Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index); - pixel.PackFromRgb24(rgb); + pixel.FromRgb24(rgb); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -328,7 +328,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba.A = paletteAlpha.Length > index ? Unsafe.Add(ref paletteAlphaRef, index) : byte.MaxValue; rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); - pixel.PackFromRgba32(rgba); + pixel.FromRgba32(rgba); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -339,7 +339,7 @@ namespace SixLabors.ImageSharp.Formats.Png int index = Unsafe.Add(ref scanlineSpanRef, o); Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index); - pixel.PackFromRgb24(rgb); + pixel.FromRgb24(rgb); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -371,7 +371,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); - pixel.PackFromRgb48(rgb48); + pixel.FromRgb48(rgb48); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -396,7 +396,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.Rgb = rgb48; rgba64.A = rgb48.Equals(rgb48Trans) ? ushort.MinValue : ushort.MaxValue; - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -411,7 +411,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba32.Rgb = rgb24; rgba32.A = rgb24.Equals(rgb24Trans) ? byte.MinValue : byte.MaxValue; - pixel.PackFromRgba32(rgba32); + pixel.FromRgba32(rgba32); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -449,7 +449,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.Rgb = rgb48; rgba64.A = rgb48.Equals(rgb48Trans) ? ushort.MinValue : ushort.MaxValue; - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -462,7 +462,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); - pixel.PackFromRgb48(rgb48); + pixel.FromRgb48(rgb48); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -480,7 +480,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); rgba.A = rgb24Trans.Equals(rgba.Rgb) ? byte.MinValue : byte.MaxValue; - pixel.PackFromRgba32(rgba); + pixel.FromRgba32(rgba); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -493,7 +493,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgb.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample); rgb.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); - pixel.PackFromRgb24(rgb); + pixel.FromRgb24(rgb); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -520,7 +520,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (3 * bytesPerSample), bytesPerSample)); - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -554,7 +554,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (3 * bytesPerSample), bytesPerSample)); - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -568,7 +568,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); rgba.A = Unsafe.Add(ref scanlineSpanRef, o + (3 * bytesPerSample)); - pixel.PackFromRgba32(rgba); + pixel.FromRgba32(rgba); Unsafe.Add(ref rowSpanRef, x) = pixel; } } diff --git a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs index cf66f5d5e8..2ed3164097 100644 --- a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.PixelFormats TPixel result = default; var rgba = new Rgba32(BinaryPrimitives.ReverseEndianness(packedValue)); - result.PackFromRgba32(rgba); + result.FromRgba32(rgba); return result; } @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static TPixel FromRGBA(byte red, byte green, byte blue, byte alpha) { TPixel color = default; - color.PackFromRgba32(new Rgba32(red, green, blue, alpha)); + color.FromRgba32(new Rgba32(red, green, blue, alpha)); return color; } diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index 3a6fb0a78c..13e35cce05 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Sets the packed representation from a scaled . /// /// The vector to create the packed representation from. - void PackFromScaledVector4(Vector4 vector); + void FromScaledVector4(Vector4 vector); /// /// Expands the packed representation into a scaled @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Sets the packed representation from a . /// /// The vector to create the packed representation from. - void PackFromVector4(Vector4 vector); + void FromVector4(Vector4 vector); /// /// Expands the packed representation into a . @@ -59,43 +59,43 @@ namespace SixLabors.ImageSharp.PixelFormats /// Packs the pixel from an value. /// /// The value. - void PackFromArgb32(Argb32 source); + void FromArgb32(Argb32 source); /// /// Packs the pixel from an value. /// /// The value. - void PackFromBgr24(Bgr24 source); + void FromBgr24(Bgr24 source); /// /// Packs the pixel from an value. /// /// The value. - void PackFromBgra32(Bgra32 source); + void FromBgra32(Bgra32 source); /// /// Packs the Pixel from an value. /// /// The value. - void PackFromGray8(Gray8 source); + void FromGray8(Gray8 source); /// /// Packs the Pixel from an value. /// /// The value. - void PackFromGray16(Gray16 source); + void FromGray16(Gray16 source); /// /// Packs the pixel from an value. /// /// The value. - void PackFromRgb24(Rgb24 source); + void FromRgb24(Rgb24 source); /// /// Packs the pixel from an value. /// /// The value. - void PackFromRgba32(Rgba32 source); + void FromRgba32(Rgba32 source); /// /// Expands the packed representation into an . @@ -107,12 +107,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// Packs the pixel from an value. /// /// The value. - void PackFromRgb48(Rgb48 source); + void FromRgb48(Rgb48 source); /// /// Packs the pixel from an value. /// /// The value. - void PackFromRgba64(Rgba64 source); + void FromRgba64(Rgba64 source); } } \ 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 19d1c5dad1..c0a38b1a33 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.PackFromScaledVector4(PorterDuffFunctions.NormalSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplySrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.AddSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -153,7 +153,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -189,7 +189,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -225,7 +225,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -261,7 +261,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.LightenSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -297,7 +297,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.OverlaySrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -333,7 +333,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -369,7 +369,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.NormalSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -405,7 +405,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplySrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -441,7 +441,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.AddSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -477,7 +477,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -513,7 +513,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -549,7 +549,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -585,7 +585,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.LightenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -621,7 +621,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.OverlaySrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -657,7 +657,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -693,7 +693,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.NormalSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -729,7 +729,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplySrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -765,7 +765,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.AddSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -801,7 +801,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -837,7 +837,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -873,7 +873,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -909,7 +909,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.LightenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -945,7 +945,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.OverlaySrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -981,7 +981,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1017,7 +1017,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.NormalSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1053,7 +1053,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplySrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1089,7 +1089,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.AddSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1125,7 +1125,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1161,7 +1161,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1197,7 +1197,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1233,7 +1233,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.LightenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1269,7 +1269,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.OverlaySrcIn(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.PackFromScaledVector4(PorterDuffFunctions.HardLightSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1341,7 +1341,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.NormalSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1377,7 +1377,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplySrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1413,7 +1413,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.AddSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1449,7 +1449,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1485,7 +1485,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1521,7 +1521,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1557,7 +1557,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.LightenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1593,7 +1593,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.OverlaySrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1629,7 +1629,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1665,7 +1665,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.NormalDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1701,7 +1701,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplyDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1737,7 +1737,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.AddDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1773,7 +1773,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1809,7 +1809,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1845,7 +1845,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1881,7 +1881,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.LightenDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1917,7 +1917,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.OverlayDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1953,7 +1953,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1989,7 +1989,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.NormalDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2025,7 +2025,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplyDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2061,7 +2061,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.AddDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2097,7 +2097,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2133,7 +2133,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2169,7 +2169,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2205,7 +2205,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.LightenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2241,7 +2241,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.OverlayDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2277,7 +2277,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2313,7 +2313,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.NormalDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2349,7 +2349,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplyDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2385,7 +2385,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.AddDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2421,7 +2421,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2457,7 +2457,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2493,7 +2493,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2529,7 +2529,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.LightenDestOver(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.PackFromScaledVector4(PorterDuffFunctions.OverlayDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlayDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2601,7 +2601,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2637,7 +2637,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.NormalDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2673,7 +2673,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplyDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2709,7 +2709,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.AddDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2745,7 +2745,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2781,7 +2781,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2817,7 +2817,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2853,7 +2853,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.LightenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2889,7 +2889,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.OverlayDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2925,7 +2925,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2961,7 +2961,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.NormalDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2997,7 +2997,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplyDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3033,7 +3033,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.AddDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3069,7 +3069,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3105,7 +3105,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3141,7 +3141,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3177,7 +3177,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.LightenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3213,7 +3213,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.OverlayDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3249,7 +3249,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3285,7 +3285,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.NormalClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3321,7 +3321,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplyClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3357,7 +3357,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.AddClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3393,7 +3393,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3429,7 +3429,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3465,7 +3465,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3501,7 +3501,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.LightenClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3537,7 +3537,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.OverlayClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3573,7 +3573,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3609,7 +3609,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.NormalXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3645,7 +3645,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplyXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3681,7 +3681,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.AddXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3717,7 +3717,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3753,7 +3753,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3789,7 +3789,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3825,7 +3825,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.LightenXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3861,7 +3861,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.OverlayXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3897,7 +3897,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders 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))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightXor(background.ToScaledVector4(), source.ToScaledVector4(), 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 0a6ef60eca..64148746e0 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -130,7 +130,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -154,7 +154,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -166,7 +166,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -178,7 +178,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -190,7 +190,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -202,7 +202,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -214,7 +214,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -226,7 +226,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -238,7 +238,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -250,7 +250,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -356,7 +356,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplySrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplySrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -368,7 +368,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplySrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplySrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -380,7 +380,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplySrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplySrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -392,7 +392,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplySrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplySrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -404,7 +404,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplySrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplySrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -416,7 +416,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplyDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplyDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -428,7 +428,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplyDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplyDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -440,7 +440,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplyDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplyDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -452,7 +452,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplyDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplyDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -464,7 +464,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplyDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplyDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -476,7 +476,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplyClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplyClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -488,7 +488,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplyXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplyXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -594,7 +594,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -606,7 +606,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -618,7 +618,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -630,7 +630,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -642,7 +642,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -654,7 +654,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -666,7 +666,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -678,7 +678,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -690,7 +690,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -702,7 +702,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -714,7 +714,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -726,7 +726,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -832,7 +832,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -844,7 +844,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -856,7 +856,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -868,7 +868,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -880,7 +880,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -892,7 +892,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -904,7 +904,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -916,7 +916,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -928,7 +928,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -940,7 +940,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -952,7 +952,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -964,7 +964,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1070,7 +1070,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1082,7 +1082,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1094,7 +1094,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1106,7 +1106,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1118,7 +1118,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1130,7 +1130,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1142,7 +1142,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1154,7 +1154,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1166,7 +1166,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1178,7 +1178,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1190,7 +1190,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1202,7 +1202,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1308,7 +1308,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1320,7 +1320,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1332,7 +1332,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1344,7 +1344,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1356,7 +1356,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1368,7 +1368,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1380,7 +1380,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1392,7 +1392,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1404,7 +1404,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1416,7 +1416,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1428,7 +1428,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1440,7 +1440,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1546,7 +1546,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1558,7 +1558,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1570,7 +1570,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1582,7 +1582,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1594,7 +1594,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1606,7 +1606,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1618,7 +1618,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1630,7 +1630,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1642,7 +1642,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1654,7 +1654,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1666,7 +1666,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1678,7 +1678,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1784,7 +1784,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlaySrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlaySrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1796,7 +1796,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlaySrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlaySrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1808,7 +1808,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlaySrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlaySrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1820,7 +1820,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlaySrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlaySrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1832,7 +1832,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlaySrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlaySrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1844,7 +1844,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlayDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlayDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1856,7 +1856,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlayDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlayDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1868,7 +1868,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlayDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlayDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1880,7 +1880,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlayDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlayDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1892,7 +1892,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlayDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlayDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1904,7 +1904,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlayClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlayClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1916,7 +1916,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlayXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlayXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2022,7 +2022,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2034,7 +2034,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2046,7 +2046,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2058,7 +2058,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2070,7 +2070,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2082,7 +2082,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2094,7 +2094,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2106,7 +2106,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2118,7 +2118,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2130,7 +2130,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2142,7 +2142,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2154,7 +2154,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Alpha8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Alpha8.cs index 730734f5f8..75b7ede827 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Alpha8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Alpha8.cs @@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(vector.W); + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(vector.W); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -77,31 +77,31 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackedValue = source.A; + public void FromArgb32(Argb32 source) => this.PackedValue = source.A; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackedValue = byte.MaxValue; + public void FromBgr24(Bgr24 source) => this.PackedValue = byte.MaxValue; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackedValue = source.A; + public void FromBgra32(Bgra32 source) => this.PackedValue = source.A; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackedValue = byte.MaxValue; + public void FromGray8(Gray8 source) => this.PackedValue = byte.MaxValue; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackedValue = byte.MaxValue; + public void FromGray16(Gray16 source) => this.PackedValue = byte.MaxValue; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackedValue = byte.MaxValue; + public void FromRgb24(Rgb24 source) => this.PackedValue = byte.MaxValue; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackedValue = source.A; + public void FromRgba32(Rgba32 source) => this.PackedValue = source.A; /// [MethodImpl(InliningOptions.ShortMethod)] @@ -113,11 +113,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackedValue = byte.MaxValue; + public void FromRgb48(Rgb48 source) => this.PackedValue = byte.MaxValue; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// /// Compares an object with the packed vector. diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs index a47d7e8e78..8fc3016314 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs @@ -169,7 +169,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -177,7 +177,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.Pack(ref vector); + public void FromVector4(Vector4 vector) => this.Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -185,11 +185,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackedValue = source.PackedValue; + public void FromArgb32(Argb32 source) => this.PackedValue = source.PackedValue; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) + public void FromBgr24(Bgr24 source) { this.R = source.R; this.G = source.G; @@ -199,7 +199,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) + public void FromBgra32(Bgra32 source) { this.R = source.R; this.G = source.G; @@ -209,7 +209,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) + public void FromGray8(Gray8 source) { this.R = source.PackedValue; this.G = source.PackedValue; @@ -219,7 +219,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) + public void FromGray16(Gray16 source) { byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); this.R = rgb; @@ -230,7 +230,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) + public void FromRgb24(Rgb24 source) { this.R = source.R; this.G = source.G; @@ -240,7 +240,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) + public void FromRgba32(Rgba32 source) { this.R = source.R; this.G = source.G; @@ -260,7 +260,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) + public void FromRgb48(Rgb48 source) { this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); @@ -270,7 +270,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) + public void FromRgba64(Rgba64 source) { this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs index 8eba08bea5..9207f046c4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -84,11 +84,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) + public void FromVector4(Vector4 vector) { Rgba32 rgba = default; - rgba.PackFromVector4(vector); - this.PackFromRgba32(rgba); + rgba.FromVector4(vector); + this.FromRgba32(rgba); } /// @@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) + public void FromArgb32(Argb32 source) { this.R = source.R; this.G = source.G; @@ -106,11 +106,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this = source; + public void FromBgr24(Bgr24 source) => this = source; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) + public void FromBgra32(Bgra32 source) { this.R = source.R; this.G = source.G; @@ -119,7 +119,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) + public void FromGray8(Gray8 source) { this.R = source.PackedValue; this.G = source.PackedValue; @@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) + public void FromGray16(Gray16 source) { byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); this.R = rgb; @@ -138,7 +138,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) + public void FromRgb24(Rgb24 source) { this.R = source.R; this.G = source.G; @@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this = source.Bgr; + public void FromRgba32(Rgba32 source) => this = source.Bgr; /// [MethodImpl(InliningOptions.ShortMethod)] @@ -161,7 +161,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) + public void FromRgb48(Rgb48 source) { this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); @@ -170,7 +170,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) + public void FromRgba64(Rgba64 source) { this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs index 295f1ca0a0..a2e4dc8802 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) + public void FromVector4(Vector4 vector) { var vector3 = new Vector3(vector.X, vector.Y, vector.Z); this.PackedValue = Pack(ref vector3); @@ -85,46 +85,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromVector4(source.ToVector4()); + public void FromArgb32(Argb32 source) => this.FromVector4(source.ToVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromVector4(source.ToVector4()); + public void FromBgra32(Bgra32 source) => this.FromVector4(source.ToVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromVector4(source.ToVector4()); + public void FromRgba32(Rgba32 source) => this.FromVector4(source.ToVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// /// Expands the packed representation into a . diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs index 5d70c9e50b..1d156222ff 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs @@ -125,7 +125,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -133,7 +133,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.Pack(ref vector); + public void FromVector4(Vector4 vector) => this.Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) + public void FromArgb32(Argb32 source) { this.R = source.R; this.G = source.G; @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) + public void FromBgr24(Bgr24 source) { this.R = source.R; this.G = source.G; @@ -161,11 +161,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this = source; + public void FromBgra32(Bgra32 source) => this = source; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) + public void FromGray8(Gray8 source) { this.R = source.PackedValue; this.G = source.PackedValue; @@ -175,7 +175,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) + public void FromGray16(Gray16 source) { byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); this.R = rgb; @@ -186,7 +186,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) + public void FromRgba32(Rgba32 source) { this.R = source.R; this.G = source.G; @@ -196,7 +196,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) + public void FromRgb24(Rgb24 source) { this.R = source.R; this.G = source.G; @@ -216,7 +216,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) + public void FromRgb48(Rgb48 source) { this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); @@ -226,7 +226,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) + public void FromRgba64(Rgba64 source) { this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs index 29ea63e20f..110b51822d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -88,46 +88,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// public override bool Equals(object obj) => obj is Bgra4444 other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs index f6dbb7811a..dcfb25a64b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -89,46 +89,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// public override bool Equals(object obj) => obj is Bgra5551 other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs index 96eeeec0d4..43a03dc5d1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector * 255F); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector * 255F); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -89,46 +89,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// public override bool Equals(object obj) => obj is Byte4 byte4 && this.Equals(byte4); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs index 0b40df8dae..2fa7df94e8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromArgb32(sp); + dp.FromArgb32(sp); } } @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromArgb32(sp); + dp.FromArgb32(sp); } } @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromArgb32(sp); + dp.FromArgb32(sp); } } @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromArgb32(sp); + dp.FromArgb32(sp); } } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromArgb32(sp); + dp.FromArgb32(sp); } } @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromArgb32(sp); + dp.FromArgb32(sp); } } @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromArgb32(sp); + dp.FromArgb32(sp); } } @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromArgb32(sp); + dp.FromArgb32(sp); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs index e895254576..950c6d5d90 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgr24(sp); + dp.FromBgr24(sp); } } @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgr24(sp); + dp.FromBgr24(sp); } } @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgr24(sp); + dp.FromBgr24(sp); } } @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgr24(sp); + dp.FromBgr24(sp); } } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgr24(sp); + dp.FromBgr24(sp); } } @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgr24(sp); + dp.FromBgr24(sp); } } @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgr24(sp); + dp.FromBgr24(sp); } } @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgr24(sp); + dp.FromBgr24(sp); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs index 2311e0bde6..f29fa78ec3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgra32(sp); + dp.FromBgra32(sp); } } @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgra32(sp); + dp.FromBgra32(sp); } } @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgra32(sp); + dp.FromBgra32(sp); } } @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgra32(sp); + dp.FromBgra32(sp); } } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgra32(sp); + dp.FromBgra32(sp); } } @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgra32(sp); + dp.FromBgra32(sp); } } @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgra32(sp); + dp.FromBgra32(sp); } } @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgra32(sp); + dp.FromBgra32(sp); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs index a2d9aa755f..1b679c50a4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray16(sp); + dp.FromGray16(sp); } } @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray16(sp); + dp.FromGray16(sp); } } @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray16(sp); + dp.FromGray16(sp); } } @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray16(sp); + dp.FromGray16(sp); } } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray16(sp); + dp.FromGray16(sp); } } @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray16(sp); + dp.FromGray16(sp); } } @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray16(sp); + dp.FromGray16(sp); } } @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray16(sp); + dp.FromGray16(sp); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs index de2c11d4d9..1be3cc4687 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray8(sp); + dp.FromGray8(sp); } } @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray8(sp); + dp.FromGray8(sp); } } @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray8(sp); + dp.FromGray8(sp); } } @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray8(sp); + dp.FromGray8(sp); } } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray8(sp); + dp.FromGray8(sp); } } @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray8(sp); + dp.FromGray8(sp); } } @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray8(sp); + dp.FromGray8(sp); } } @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray8(sp); + dp.FromGray8(sp); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs index ad4ee2764e..c6a7c70694 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb24(sp); + dp.FromRgb24(sp); } } @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb24(sp); + dp.FromRgb24(sp); } } @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb24(sp); + dp.FromRgb24(sp); } } @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb24(sp); + dp.FromRgb24(sp); } } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb24(sp); + dp.FromRgb24(sp); } } @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb24(sp); + dp.FromRgb24(sp); } } @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb24(sp); + dp.FromRgb24(sp); } } @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb24(sp); + dp.FromRgb24(sp); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs index 0a1ef03873..dcc0f38024 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb48(sp); + dp.FromRgb48(sp); } } @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb48(sp); + dp.FromRgb48(sp); } } @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb48(sp); + dp.FromRgb48(sp); } } @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb48(sp); + dp.FromRgb48(sp); } } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb48(sp); + dp.FromRgb48(sp); } } @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb48(sp); + dp.FromRgb48(sp); } } @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb48(sp); + dp.FromRgb48(sp); } } @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb48(sp); + dp.FromRgb48(sp); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs index bd3e014b4d..63dbc7405d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba32(sp); + dp.FromRgba32(sp); } } @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba32(sp); + dp.FromRgba32(sp); } } @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba32(sp); + dp.FromRgba32(sp); } } @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba32(sp); + dp.FromRgba32(sp); } } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba32(sp); + dp.FromRgba32(sp); } } @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba32(sp); + dp.FromRgba32(sp); } } @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba32(sp); + dp.FromRgba32(sp); } } @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba32(sp); + dp.FromRgba32(sp); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs index e6f9b37a70..f92fe8ec70 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba64(sp); + dp.FromRgba64(sp); } } @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba64(sp); + dp.FromRgba64(sp); } } @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba64(sp); + dp.FromRgba64(sp); } } @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba64(sp); + dp.FromRgba64(sp); } } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba64(sp); + dp.FromRgba64(sp); } } @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba64(sp); + dp.FromRgba64(sp); } } @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba64(sp); + dp.FromRgba64(sp); } } @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba64(sp); + dp.FromRgba64(sp); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Gray16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Gray16.cs index 788278be4e..2e98a28ada 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Gray16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Gray16.cs @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) + public void FromVector4(Vector4 vector) { vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max * Average; this.PackedValue = (ushort)MathF.Round(vector.X + vector.Y + vector.Z); @@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) + public void FromArgb32(Argb32 source) { this.PackedValue = ImageMaths.Get16BitBT709Luminance( ImageMaths.UpscaleFrom8BitTo16Bit(source.R), @@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) + public void FromBgr24(Bgr24 source) { this.PackedValue = ImageMaths.Get16BitBT709Luminance( ImageMaths.UpscaleFrom8BitTo16Bit(source.R), @@ -98,7 +98,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) + public void FromBgra32(Bgra32 source) { this.PackedValue = ImageMaths.Get16BitBT709Luminance( ImageMaths.UpscaleFrom8BitTo16Bit(source.R), @@ -108,15 +108,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackedValue = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue); + public void FromGray8(Gray8 source) => this.PackedValue = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackedValue = source.PackedValue; + public void FromGray16(Gray16 source) => this.PackedValue = source.PackedValue; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) + public void FromRgb24(Rgb24 source) { this.PackedValue = ImageMaths.Get16BitBT709Luminance( ImageMaths.UpscaleFrom8BitTo16Bit(source.R), @@ -126,7 +126,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) + public void FromRgba32(Rgba32 source) { this.PackedValue = ImageMaths.Get16BitBT709Luminance( ImageMaths.UpscaleFrom8BitTo16Bit(source.R), @@ -147,11 +147,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackedValue = ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B); + public void FromRgb48(Rgb48 source) => this.PackedValue = ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackedValue = ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B); + public void FromRgba64(Rgba64 source) => this.PackedValue = ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B); /// public override bool Equals(object obj) => obj is Gray16 other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs index 8a9ec540dc..d23fda7991 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) + public void FromVector4(Vector4 vector) { vector *= MaxBytes; vector += Half; @@ -80,31 +80,31 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + public void FromArgb32(Argb32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + public void FromBgr24(Bgr24 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + public void FromBgra32(Bgra32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackedValue = source.PackedValue; + public void FromGray8(Gray8 source) => this.PackedValue = source.PackedValue; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackedValue = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + public void FromGray16(Gray16 source) => this.PackedValue = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + public void FromRgb24(Rgb24 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + public void FromRgba32(Rgba32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) + public void FromRgb48(Rgb48 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance( ImageMaths.DownScaleFrom16BitTo8Bit(source.R), ImageMaths.DownScaleFrom16BitTo8Bit(source.G), @@ -126,7 +126,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) + public void FromRgba64(Rgba64 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance( ImageMaths.DownScaleFrom16BitTo8Bit(source.R), ImageMaths.DownScaleFrom16BitTo8Bit(source.G), diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs index a1811e147e..8323cf3e8a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) + public void FromScaledVector4(Vector4 vector) { float scaled = vector.X; scaled *= 2F; @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.PackedValue = HalfTypeHelper.Pack(vector.X); + public void FromVector4(Vector4 vector) => this.PackedValue = HalfTypeHelper.Pack(vector.X); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -78,46 +78,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// /// Expands the packed representation into a . diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs index 381650aec5..cb915459bc 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs @@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) + public void FromScaledVector4(Vector4 vector) { Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; scaled -= Vector2.One; @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(vector.X, vector.Y); + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(vector.X, vector.Y); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -89,46 +89,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// /// Expands the packed representation into a . diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs index b7d6687eab..9f60ca8c77 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs @@ -63,11 +63,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) + public void FromScaledVector4(Vector4 vector) { vector *= 2F; vector -= Vector4.One; - this.PackFromVector4(vector); + this.FromVector4(vector); } /// @@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -97,46 +97,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// public override bool Equals(object obj) => obj is HalfVector4 other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs index 9999cfe03b..d39cfd402e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) + public void FromScaledVector4(Vector4 vector) { Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; scaled -= Vector2.One; @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) + public void FromVector4(Vector4 vector) { var vector2 = new Vector2(vector.X, vector.Y); this.PackedValue = Pack(vector2); @@ -95,46 +95,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// /// Expands the packed representation into a . diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs index 5f9124bdce..82698d5085 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs @@ -66,11 +66,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) + public void FromScaledVector4(Vector4 vector) { vector *= 2F; vector -= Vector4.One; - this.PackFromVector4(vector); + this.FromVector4(vector); } /// @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -100,46 +100,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// public override bool Equals(object obj) => obj is NormalizedByte4 other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs index 0cd8d9408f..b9cab1e7d3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) + public void FromScaledVector4(Vector4 vector) { Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; scaled -= Vector2.One; @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) + public void FromVector4(Vector4 vector) { var vector2 = new Vector2(vector.X, vector.Y); this.PackedValue = Pack(vector2); @@ -95,46 +95,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// /// Expands the packed representation into a . diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs index 21aac4d248..3bc74e6c67 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs @@ -66,11 +66,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) + public void FromScaledVector4(Vector4 vector) { vector *= 2F; vector -= Vector4.One; - this.PackFromVector4(vector); + this.FromVector4(vector); } /// @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -102,46 +102,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// public override bool Equals(object obj) => obj is NormalizedShort4 other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs index 878b2342f9..6dc623518d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) + public void FromVector4(Vector4 vector) { var vector2 = new Vector2(vector.X, vector.Y); this.PackedValue = Pack(vector2); @@ -83,46 +83,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// /// Expands the packed representation into a . diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs index 0113027d62..293fe0acbf 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.PixelFormats var vector = new Vector4(color.ToVector3(), 1F); Rgb24 rgb = default; - rgb.PackFromScaledVector4(vector); + rgb.FromScaledVector4(vector); return rgb; } @@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -103,7 +103,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.Pack(ref vector); + public void FromVector4(Vector4 vector) => this.Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) + public void FromArgb32(Argb32 source) { this.R = source.R; this.G = source.G; @@ -120,7 +120,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) + public void FromBgr24(Bgr24 source) { this.R = source.R; this.G = source.G; @@ -129,7 +129,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) + public void FromBgra32(Bgra32 source) { this.R = source.R; this.G = source.G; @@ -138,7 +138,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) + public void FromGray8(Gray8 source) { this.R = source.PackedValue; this.G = source.PackedValue; @@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) + public void FromGray16(Gray16 source) { byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); this.R = rgb; @@ -157,11 +157,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this = source; + public void FromRgb24(Rgb24 source) => this = source; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this = source.Rgb; + public void FromRgba32(Rgba32 source) => this = source.Rgb; /// [MethodImpl(InliningOptions.ShortMethod)] @@ -175,7 +175,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) + public void FromRgb48(Rgb48 source) { this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); @@ -184,7 +184,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) + public void FromRgba64(Rgba64 source) { this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs index 815bf8c913..81497e5f18 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) + public void FromVector4(Vector4 vector) { vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; this.R = (ushort)MathF.Round(vector.X); @@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) + public void FromArgb32(Argb32 source) { this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); @@ -106,7 +106,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) + public void FromBgr24(Bgr24 source) { this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); @@ -115,7 +115,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) + public void FromBgra32(Bgra32 source) { this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); @@ -124,11 +124,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this = source.Rgb; + public void FromRgba64(Rgba64 source) => this = source.Rgb; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) + public void FromGray8(Gray8 source) { ushort rgb = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue); this.R = rgb; @@ -138,7 +138,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) + public void FromGray16(Gray16 source) { this.R = source.PackedValue; this.G = source.PackedValue; @@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) + public void FromRgb24(Rgb24 source) { this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); @@ -156,7 +156,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) + public void FromRgba32(Rgba32 source) { this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); @@ -175,7 +175,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this = source; + public void FromRgb48(Rgb48 source) => this = source; /// public override bool Equals(object obj) => obj is Rgb48 rgb48 && this.Equals(rgb48); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs index 7f3e3a8706..895added1b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -89,46 +89,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// public override bool Equals(object obj) => obj is Rgba1010102 other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index e866d1350a..5a16704ef0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -181,7 +181,7 @@ namespace SixLabors.ImageSharp.PixelFormats var vector = new Vector4(color.ToVector3(), 1F); Rgba32 rgba = default; - rgba.PackFromScaledVector4(vector); + rgba.FromScaledVector4(vector); return rgba; } @@ -224,7 +224,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -232,7 +232,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.Pack(ref vector); + public void FromVector4(Vector4 vector) => this.Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -240,7 +240,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) + public void FromArgb32(Argb32 source) { this.R = source.R; this.G = source.G; @@ -250,7 +250,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) + public void FromBgr24(Bgr24 source) { this.Bgr = source; this.A = byte.MaxValue; @@ -258,7 +258,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) + public void FromBgra32(Bgra32 source) { this.R = source.R; this.G = source.G; @@ -268,7 +268,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) + public void FromGray8(Gray8 source) { this.R = source.PackedValue; this.G = source.PackedValue; @@ -278,7 +278,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) + public void FromGray16(Gray16 source) { byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); this.R = rgb; @@ -289,7 +289,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) + public void FromRgb24(Rgb24 source) { this.Rgb = source; this.A = byte.MaxValue; @@ -297,7 +297,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this = source; + public void FromRgba32(Rgba32 source) => this = source; /// [MethodImpl(InliningOptions.ShortMethod)] @@ -308,7 +308,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) + public void FromRgb48(Rgb48 source) { this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); @@ -318,7 +318,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) + public void FromRgba64(Rgba64 source) { this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs index 2d1a676705..5ae5492e23 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs @@ -103,7 +103,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) + public void FromVector4(Vector4 vector) { vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; this.R = (ushort)MathF.Round(vector.X); @@ -126,7 +126,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) + public void FromArgb32(Argb32 source) { this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); @@ -136,7 +136,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) + public void FromBgr24(Bgr24 source) { this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); @@ -146,7 +146,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) + public void FromBgra32(Bgra32 source) { this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); @@ -156,7 +156,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) + public void FromGray8(Gray8 source) { ushort rgb = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue); this.R = rgb; @@ -167,7 +167,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) + public void FromGray16(Gray16 source) { this.R = source.PackedValue; this.G = source.PackedValue; @@ -177,7 +177,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) + public void FromRgb24(Rgb24 source) { this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); @@ -187,7 +187,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) + public void FromRgba32(Rgba32 source) { this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); @@ -207,7 +207,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) + public void FromRgb48(Rgb48 source) { this.Rgb = source; this.A = ushort.MaxValue; @@ -215,7 +215,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this = source; + public void FromRgba64(Rgba64 source) => this = source; /// public override bool Equals(object obj) => obj is Rgba64 rgba64 && this.Equals(rgba64); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs index 25b8155d31..ff4c69d701 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs @@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) + public void FromVector4(Vector4 vector) { vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); this.R = vector.X; @@ -124,46 +124,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// /// Converts the value of this instance to a hexadecimal string. diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs index 69a4e35e93..96fe15ed61 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) + public void FromScaledVector4(Vector4 vector) { Vector2 scaled = new Vector2(vector.X, vector.Y) * 65534F; scaled -= new Vector2(32767F); @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) + public void FromVector4(Vector4 vector) { var vector2 = new Vector2(vector.X, vector.Y); this.PackedValue = Pack(vector2); @@ -101,46 +101,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// /// Expands the packed representation into a . diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs index 653bc030f8..d224f8eb4e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs @@ -72,11 +72,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) + public void FromScaledVector4(Vector4 vector) { vector *= 65534F; vector -= new Vector4(32767F); - this.PackFromVector4(vector); + this.FromVector4(vector); } /// @@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -106,46 +106,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// public override bool Equals(object obj) => obj is Short4 other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs index 66966543fc..2708af0749 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromArgb32(sp); + dp.FromArgb32(sp); } } @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Argb32 dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromScaledVector4(sp.ToScaledVector4()); + dp.FromScaledVector4(sp.ToScaledVector4()); } } @@ -98,7 +98,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromBgr24(sp); + dp.FromBgr24(sp); } } @@ -133,7 +133,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromScaledVector4(sp.ToScaledVector4()); + dp.FromScaledVector4(sp.ToScaledVector4()); } } @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromBgra32(sp); + dp.FromBgra32(sp); } } @@ -203,7 +203,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromScaledVector4(sp.ToScaledVector4()); + dp.FromScaledVector4(sp.ToScaledVector4()); } } @@ -238,7 +238,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray8 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromGray8(sp); + dp.FromGray8(sp); } } @@ -273,7 +273,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Gray8 dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromScaledVector4(sp.ToScaledVector4()); + dp.FromScaledVector4(sp.ToScaledVector4()); } } @@ -308,7 +308,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray16 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromGray16(sp); + dp.FromGray16(sp); } } @@ -343,7 +343,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Gray16 dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromScaledVector4(sp.ToScaledVector4()); + dp.FromScaledVector4(sp.ToScaledVector4()); } } @@ -378,7 +378,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromRgb24(sp); + dp.FromRgb24(sp); } } @@ -413,7 +413,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromScaledVector4(sp.ToScaledVector4()); + dp.FromScaledVector4(sp.ToScaledVector4()); } } @@ -448,7 +448,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromRgba32(sp); + dp.FromRgba32(sp); } } @@ -483,7 +483,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromScaledVector4(sp.ToScaledVector4()); + dp.FromScaledVector4(sp.ToScaledVector4()); } } @@ -518,7 +518,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromRgb48(sp); + dp.FromRgb48(sp); } } @@ -553,7 +553,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromScaledVector4(sp.ToScaledVector4()); + dp.FromScaledVector4(sp.ToScaledVector4()); } } @@ -588,7 +588,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromRgba64(sp); + dp.FromRgba64(sp); } } @@ -623,7 +623,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromScaledVector4(sp.ToScaledVector4()); + dp.FromScaledVector4(sp.ToScaledVector4()); } } diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index f1b40e81f0..926b234d75 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static PixelOperations Instance { get; } = default(TPixel).CreatePixelOperations(); /// - /// Bulk version of + /// Bulk version of /// /// The to the source vectors. /// The to the destination colors. @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); ref TPixel dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromVector4(sp); + dp.FromVector4(sp); } } @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// Bulk version of + /// Bulk version of /// /// The to the source vectors. /// The to the destination colors. @@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); ref TPixel dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromScaledVector4(sp); + dp.FromScaledVector4(sp); } } @@ -155,7 +155,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); ref TPixel2 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromScaledVector4(sp.ToScaledVector4()); + dp.FromScaledVector4(sp.ToScaledVector4()); } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs index ebf9c8dec2..4165cf024e 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs @@ -165,7 +165,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution currentPassPixel.ToVector4(), currentTargetPixel.ToVector4()); - currentTargetPixel.PackFromVector4(pixelValue); + currentTargetPixel.FromVector4(pixelValue); } } }); diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffuserBase.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffuserBase.cs index b407841f20..642da2f001 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffuserBase.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffuserBase.cs @@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering var offsetColor = pixel.ToVector4(); Vector4 result = ((error * coefficient) / this.divisorVector) + offsetColor; - pixel.PackFromVector4(result); + pixel.FromVector4(result); } } } diff --git a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs index 6ad4dcba97..1b17c470ed 100644 --- a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs @@ -135,7 +135,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects float blue = MathF.Abs(blueBin[maxIndex] / maxIntensity); ref TPixel pixel = ref targetRow[x]; - pixel.PackFromVector4( + pixel.FromVector4( new Vector4(red, green, blue, sourceRow[x].ToVector4().W)); } } diff --git a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs index e20b42eb7c..d3a44c066e 100644 --- a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters { ref TPixel pixel = ref row[x]; var vector = Vector4.Transform(pixel.ToVector4(), matrix); - pixel.PackFromVector4(vector); + pixel.FromVector4(vector); } } }); diff --git a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs index e90b352258..580adc7fe9 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization int luminance = this.GetLuminance(sourcePixel, this.LuminanceLevels); float luminanceEqualized = cdf[luminance] / numberOfPixelsMinusCdfMin; - pixels[i].PackFromVector4(new Vector4(luminanceEqualized)); + pixels[i].FromVector4(new Vector4(luminanceEqualized)); } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs index 29742725a0..1eeb0be410 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs @@ -499,7 +499,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization // Set the color of the palette entry var vector = Vector3.Clamp(new Vector3(this.red, this.green, this.blue) / this.pixelCount, Vector3.Zero, new Vector3(255)); TPixel pixel = default; - pixel.PackFromRgba32(new Rgba32((byte)vector.X, (byte)vector.Y, (byte)vector.Z, byte.MaxValue)); + pixel.FromRgba32(new Rgba32((byte)vector.X, (byte)vector.Y, (byte)vector.Z, byte.MaxValue)); palette[index] = pixel; // Consume the next palette index diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 4ef1659605..dd947f337d 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -199,7 +199,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization 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); + color.FromScaledVector4(new Vector4(r, g, b, a) / weight / 255F); } } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index 790eb80482..e12b91eab9 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -218,7 +218,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // Reverse the premultiplication Vector4Utils.UnPremultiply(ref sum); - dest.PackFromVector4(sum); + dest.FromVector4(sum); } } }); diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index bad8eab3af..50af26aebf 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -227,7 +227,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // Reverse the premultiplication Vector4Utils.UnPremultiply(ref sum); - dest.PackFromVector4(sum); + dest.FromVector4(sum); } } }); diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index eaa52a9750..e39c464f1a 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk for (int i = 0; i < this.Count; i++) { - Unsafe.Add(ref d, i).PackFromVector4(Unsafe.Add(ref s, i)); + Unsafe.Add(ref d, i).FromVector4(Unsafe.Add(ref s, i)); } } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs index 7e7dfb3652..5272351045 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk { int i4 = i * 4; var c = default(TPixel); - c.PackFromRgba32(new Rgba32(s[i4], s[i4 + 1], s[i4 + 2], s[i4 + 3])); + c.FromRgba32(new Rgba32(s[i4], s[i4 + 1], s[i4 + 2], s[i4 + 3])); d[i] = c; } } diff --git a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs index ff2e57b974..729971548c 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs @@ -129,7 +129,7 @@ namespace SixLabors.ImageSharp.Benchmarks float distance = Vector2.Distance(centre, new Vector2(offsetX, offsetY)); Vector4 sourceColor = sourcePixels[offsetX, offsetY].ToVector4(); TPixel packed = default(TPixel); - packed.PackFromVector4( + packed.FromVector4( PremultipliedLerp( sourceColor, glowColor.ToVector4(), diff --git a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs index 32f723e72a..639b3fe81a 100644 --- a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs @@ -154,7 +154,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing vec.W = alpha; TPixel fillColor = default; - fillColor.PackFromVector4(vec); + fillColor.FromVector4(vec); using (Image image = provider.GetImage()) { diff --git a/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs b/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs index a8fb187ced..94e12f8581 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing var c = NamedColors.Red.ToVector4(); c.W *= 0.5f; var pixel = default(TPixel); - pixel.PackFromVector4(c); + pixel.FromVector4(c); img.Mutate( x => x.Fill( diff --git a/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs b/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs index dedb094bc2..341d67f0f1 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { var rgba = new Rgba32((byte)(i + 1), (byte)(j + 1), (byte)200, (byte)255); var color = default(TPixel); - color.PackFromRgba32(rgba); + color.FromRgba32(rgba); pixels[i, j] = color; } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs index 57d92fa151..7acce84cea 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs @@ -103,7 +103,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils var v = new Vector4(val, val, val, 1); Rgba32 color = default; - color.PackFromVector4(v); + color.FromVector4(v); int yy = by * 8 + y; int xx = bx * 8 + x; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs index bcfabca390..f5618d26d2 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils var v = new Vector4(val0, val1, val2, 1); Rgba32 color = default; - color.PackFromVector4(v); + color.FromVector4(v); int yy = by * 8 + y; int xx = bx * 8 + x; diff --git a/tests/ImageSharp.Tests/Issues/Issue594.cs b/tests/ImageSharp.Tests/Issues/Issue594.cs index 4a0683fba7..48e355ea78 100644 --- a/tests/ImageSharp.Tests/Issues/Issue594.cs +++ b/tests/ImageSharp.Tests/Issues/Issue594.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Tests.Issues // Test PackFromScaledVector4. var pixel = default(NormalizedByte4); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); Assert.Equal(0x81818181, pixel.PackedValue); // Test Ordering @@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Tests.Issues float w = -0.7f; Assert.Equal(0xA740DA0D, new NormalizedByte4(x, y, z, w).PackedValue); var n = default(NormalizedByte4); - n.PackFromRgba32(new Rgba32(141, 90, 192, 39)); + n.FromRgba32(new Rgba32(141, 90, 192, 39)); Assert.Equal(0xA740DA0D, n.PackedValue); Assert.Equal((uint)958796544, new NormalizedByte4(0.0008f, 0.15f, 0.30f, 0.45f).PackedValue); @@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.Tests.Issues // Test PackFromScaledVector4. var pixel = default(NormalizedShort4); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); Assert.Equal((ulong)0x7FFF7FFF7FFF7FFF, pixel.PackedValue); // Test Ordering @@ -192,7 +192,7 @@ namespace SixLabors.ImageSharp.Tests.Issues // Test PackFromScaledVector4. var pixel = default(Short4); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); Assert.Equal((ulong)0x7FFF7FFF7FFF7FFF, pixel.PackedValue); // Test clamping. diff --git a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs index 37e7d94e4d..067c1a9779 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); // Act - alpha.PackFromScaledVector4(scaled); + alpha.FromScaledVector4(scaled); byte actual = alpha.PackedValue; // Assert diff --git a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs index 6186793c5b..31b9a53a04 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats uint expected = 0xFFFFFFFF; // act - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs index 96589a03e0..ce284f4201 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public void PackFromRgba32() { var rgb = default(Bgr24); - rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); + rgb.FromRgba32(new Rgba32(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public void PackFromVector4() { var rgb = default(Bgr24); - rgb.PackFromVector4(Vec(1, 2, 3, 4)); + rgb.FromVector4(Vec(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs index 8cbbf558d8..5033788b84 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var pixel = default(Bgr565); // act - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); ushort actual = pixel.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs index 1b890ac494..93993cc399 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public void PackFromRgba32() { var rgb = default(Rgb24); - rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); + rgb.FromRgba32(new Rgba32(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public void PackFromVector4() { var c = default(Bgra32); - c.PackFromVector4(Vec(1, 2, 3, 4)); + c.FromVector4(Vec(1, 2, 3, 4)); Assert.Equal(1, c.R); Assert.Equal(2, c.G); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs index a2fc1a0520..3f6b7653f4 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var bgra = default(Bgra4444); // act - bgra.PackFromScaledVector4(scaled); + bgra.FromScaledVector4(scaled); ushort actual = bgra.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs index 084dfbd97c..eaf397bb5b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs @@ -53,10 +53,10 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Vector4 scaled = new Bgra5551(Vector4.One).ToScaledVector4(); int expected = 0xFFFF; var pixel = default(Bgra5551); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); // act - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); ushort actual = pixel.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs index de1c749f6c..c172bbdaca 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats uint expected = 0xFFFFFFFF; // act - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs index db4fa70197..69a44a9bbf 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Vector4 scaled = new Gray16(expected).ToScaledVector4(); // Act - gray.PackFromScaledVector4(scaled); + gray.FromScaledVector4(scaled); ushort actual = gray.PackedValue; // Assert @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var vector = new Gray16(expected).ToVector4(); // Act - gray.PackFromVector4(vector); + gray.FromVector4(vector); ushort actual = gray.PackedValue; // Assert @@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats ushort expected = ImageMaths.Get16BitBT709Luminance(scaledRgb, scaledRgb, scaledRgb); // Act - gray.PackFromRgba32(new Rgba32(rgb, rgb, rgb)); + gray.FromRgba32(new Rgba32(rgb, rgb, rgb)); ushort actual = gray.PackedValue; // Assert diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs index aaca6c8776..7886be9e02 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Vector4 scaled = new Gray8(expected).ToScaledVector4(); // Act - gray.PackFromScaledVector4(scaled); + gray.FromScaledVector4(scaled); byte actual = gray.PackedValue; // Assert @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var vector = new Gray8(expected).ToVector4(); // Act - gray.PackFromVector4(vector); + gray.FromVector4(vector); byte actual = gray.PackedValue; // Assert @@ -98,7 +98,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats byte expected = ImageMaths.Get8BitBT709Luminance(rgb, rgb, rgb); // Act - gray.PackFromRgba32(new Rgba32(rgb, rgb, rgb)); + gray.FromRgba32(new Rgba32(rgb, rgb, rgb)); byte actual = gray.PackedValue; // Assert diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs index fed55af6f7..a503db01cb 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var halfSingle = default(HalfSingle); // act - halfSingle.PackFromScaledVector4(scaled); + halfSingle.FromScaledVector4(scaled); ushort actual = halfSingle.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs index c775e3a0de..a892b84137 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var halfVector = default(HalfVector2); // act - halfVector.PackFromScaledVector4(scaled); + halfVector.FromScaledVector4(scaled); uint actual = halfVector.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs index 540a1ed08b..02a05a76f9 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats ulong expected = 13547034390470638592uL; // act - halfVector4.PackFromScaledVector4(scaled); + halfVector4.FromScaledVector4(scaled); ulong actual = halfVector4.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs index 98b747a94f..faaeae6cc1 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats uint expected = 0x8181; // act - byte2.PackFromScaledVector4(scaled); + byte2.FromScaledVector4(scaled); uint actual = byte2.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs index d9cca360b2..4465fbaed3 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats uint expected = 0x81818181; // act - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs index 83eab82ac8..4f66d04e35 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats uint expected = 0x80018001; // act - short2.PackFromScaledVector4(scaled); + short2.FromScaledVector4(scaled); uint actual = short2.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs index 40b2d05e31..b93960dbf8 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs @@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats ulong expected = 0x7FFF7FFF7FFF7FFF; // act - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); ulong actual = pixel.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 8a0aee1a7c..ef57458c96 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { - expected[i].PackFromGray8(new Gray8(source[i])); + expected[i].FromGray8(new Gray8(source[i])); } TestOperation( @@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { - gray.PackFromScaledVector4(source[i].ToScaledVector4()); + gray.FromScaledVector4(source[i].ToScaledVector4()); expected[i] = gray.PackedValue; } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i2 = i * 2; - expected[i].PackFromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); + expected[i].FromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); } TestOperation( @@ -138,7 +138,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i2 = i * 2; - gray.PackFromScaledVector4(source[i].ToScaledVector4()); + gray.FromScaledVector4(source[i].ToScaledVector4()); OctetBytes bytes = Unsafe.As(ref gray); expected[i2] = bytes[0]; expected[i2 + 1] = bytes[1]; @@ -171,7 +171,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { - expected[i].PackFromGray8(new Gray8(source[i])); + expected[i].FromGray8(new Gray8(source[i])); } TestOperation( @@ -191,7 +191,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { - gray.PackFromScaledVector4(source[i].ToScaledVector4()); + gray.FromScaledVector4(source[i].ToScaledVector4()); expected[i] = gray.PackedValue; } @@ -213,7 +213,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i2 = i * 2; - expected[i].PackFromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); + expected[i].FromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); } TestOperation( @@ -234,7 +234,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i2 = i * 2; - gray.PackFromScaledVector4(source[i].ToScaledVector4()); + gray.FromScaledVector4(source[i].ToScaledVector4()); OctetBytes bytes = Unsafe.As(ref gray); expected[i2] = bytes[0]; expected[i2 + 1] = bytes[1]; @@ -341,7 +341,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < expected.Length; i++) { - expected[i].PackFromVector4(source[i]); + expected[i].FromVector4(source[i]); } return expected; } @@ -352,7 +352,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < expected.Length; i++) { - expected[i].PackFromScaledVector4(source[i]); + expected[i].FromScaledVector4(source[i]); } return expected; } @@ -446,7 +446,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { int i4 = i * 4; - expected[i].PackFromArgb32(new Argb32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); + expected[i].FromArgb32(new Argb32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); } TestOperation( @@ -467,7 +467,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i4 = i * 4; - argb.PackFromScaledVector4(source[i].ToScaledVector4()); + argb.FromScaledVector4(source[i].ToScaledVector4()); expected[i4] = argb.A; expected[i4 + 1] = argb.R; @@ -493,7 +493,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { int i3 = i * 3; - expected[i].PackFromBgr24(new Bgr24(source[i3 + 2], source[i3 + 1], source[i3])); + expected[i].FromBgr24(new Bgr24(source[i3 + 2], source[i3 + 1], source[i3])); } TestOperation( @@ -514,7 +514,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i3 = i * 3; - bgr.PackFromScaledVector4(source[i].ToScaledVector4()); + bgr.FromScaledVector4(source[i].ToScaledVector4()); expected[i3] = bgr.B; expected[i3 + 1] = bgr.G; expected[i3 + 2] = bgr.R; @@ -538,7 +538,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { int i4 = i * 4; - expected[i].PackFromBgra32(new Bgra32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); + expected[i].FromBgra32(new Bgra32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); } TestOperation( @@ -559,7 +559,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i4 = i * 4; - bgra.PackFromScaledVector4(source[i].ToScaledVector4()); + bgra.FromScaledVector4(source[i].ToScaledVector4()); expected[i4] = bgra.B; expected[i4 + 1] = bgra.G; expected[i4 + 2] = bgra.R; @@ -584,7 +584,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { int i3 = i * 3; - expected[i].PackFromRgb24(new Rgb24(source[i3 + 0], source[i3 + 1], source[i3 + 2])); + expected[i].FromRgb24(new Rgb24(source[i3 + 0], source[i3 + 1], source[i3 + 2])); } TestOperation( @@ -605,7 +605,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i3 = i * 3; - rgb.PackFromScaledVector4(source[i].ToScaledVector4()); + rgb.FromScaledVector4(source[i].ToScaledVector4()); expected[i3] = rgb.R; expected[i3 + 1] = rgb.G; expected[i3 + 2] = rgb.B; @@ -629,7 +629,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { int i4 = i * 4; - expected[i].PackFromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); + expected[i].FromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); } TestOperation( @@ -650,7 +650,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i4 = i * 4; - rgba.PackFromScaledVector4(source[i].ToScaledVector4()); + rgba.FromScaledVector4(source[i].ToScaledVector4()); expected[i4] = rgba.R; expected[i4 + 1] = rgba.G; expected[i4 + 2] = rgba.B; @@ -675,7 +675,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i6 = i * 6; - expected[i].PackFromRgb48(MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]); + expected[i].FromRgb48(MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]); } TestOperation( @@ -696,7 +696,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i6 = i * 6; - rgb.PackFromScaledVector4(source[i].ToScaledVector4()); + rgb.FromScaledVector4(source[i].ToScaledVector4()); OctetBytes rgb48Bytes = Unsafe.As(ref rgb); expected[i6] = rgb48Bytes[0]; expected[i6 + 1] = rgb48Bytes[1]; @@ -724,7 +724,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i8 = i * 8; - expected[i].PackFromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); + expected[i].FromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); } TestOperation( @@ -745,7 +745,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i8 = i * 8; - rgba.PackFromScaledVector4(source[i].ToScaledVector4()); + rgba.FromScaledVector4(source[i].ToScaledVector4()); OctetBytes rgba64Bytes = Unsafe.As(ref rgba); expected[i8] = rgba64Bytes[0]; expected[i8 + 1] = rgba64Bytes[1]; @@ -799,7 +799,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < result.Length; i++) { Vector4 v = GetVector(rnd); - result[i].PackFromVector4(v); + result[i].FromVector4(v); } return result; @@ -814,7 +814,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < result.Length; i++) { Vector4 v = GetVector(rnd); - result[i].PackFromScaledVector4(v); + result[i].FromScaledVector4(v); } return result; diff --git a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs index 135843e35f..d4347cae65 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs @@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act Vector4 scaled = rg32.ToScaledVector4(); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs index aa6d9024cd..918a147d9e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public void PackFromRgba32() { var rgb = default(Rgb24); - rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); + rgb.FromRgba32(new Rgba32(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public void PackFromVector4() { var rgb = default(Rgb24); - rgb.PackFromVector4(Vec(1, 2, 3, 4)); + rgb.FromVector4(Vec(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index 16dfd7f577..444a627926 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act Vector4 scaled = short3.ToScaledVector4(); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); // assert Assert.Equal(expected, pixel); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs index 243d4a44c9..16aad79a0c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs @@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act Vector4 scaled = rgba.ToScaledVector4(); - actual.PackFromScaledVector4(scaled); + actual.FromScaledVector4(scaled); // assert Assert.Equal(expected, actual.PackedValue); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs index 30a5f961b7..df83d14fbc 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act Vector4 scaled = rgba.ToScaledVector4(); - actual.PackFromScaledVector4(scaled); + actual.FromScaledVector4(scaled); // assert Assert.Equal(expected, actual.PackedValue); @@ -190,7 +190,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(0x1a, 0, 0x80, 0); // act - actual.PackFromRgba32(rgba); + actual.FromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -205,8 +205,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(0x1a, 0, 0x80, 0); // act - rgba.PackFromRgba32(expected); - actual.PackFromRgba32(rgba); + rgba.FromRgba32(expected); + actual.FromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -221,8 +221,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Bgra32(0x1a, 0, 0x80, 0); // act - rgba.PackFromBgra32(expected); - actual.PackFromRgba32(rgba); + rgba.FromBgra32(expected); + actual.FromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -237,8 +237,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Argb32(0x1a, 0, 0x80, 0); // act - rgba.PackFromArgb32(expected); - actual.PackFromRgba32(rgba); + rgba.FromArgb32(expected); + actual.FromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -253,8 +253,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgb48(65535, 0, 65535); // act - input.PackFromRgb48(expected); - actual.PackFromScaledVector4(input.ToScaledVector4()); + input.FromRgb48(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -269,8 +269,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba64(65535, 0, 65535, 0); // act - input.PackFromRgba64(expected); - actual.PackFromScaledVector4(input.ToScaledVector4()); + input.FromRgba64(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index e9ac5377d2..d6a9db66f8 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act Vector4 scaled = short4.ToScaledVector4(); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); ulong actual = pixel.PackedValue; // assert @@ -71,8 +71,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { var zero = default(Rgba64); var one = default(Rgba64); - zero.PackFromVector4(Vector4.One * -1234.0f); - one.PackFromVector4(Vector4.One * 1234.0f); + zero.FromVector4(Vector4.One * -1234.0f); + one.FromVector4(Vector4.One * 1234.0f); Assert.Equal(Vector4.Zero, zero.ToVector4()); Assert.Equal(Vector4.One, one.ToVector4()); } diff --git a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs index 9b5fceac77..a6fec9e51a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs @@ -124,8 +124,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgb48(65535, 0, 65535); // act - input.PackFromRgb48(expected); - actual.PackFromScaledVector4(input.ToScaledVector4()); + input.FromRgb48(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -140,8 +140,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba64(65535, 0, 65535, 0); // act - input.PackFromRgba64(expected); - actual.PackFromScaledVector4(input.ToScaledVector4()); + input.FromRgba64(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs index 5f2f45b3be..b15384bf6b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act Vector4 scaled = short2.ToScaledVector4(); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert @@ -103,7 +103,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(20, 38, 0, 255); // act - short2.PackFromRgba32(expected); + short2.FromRgba32(expected); actual = short2.ToRgba32(); // assert @@ -119,8 +119,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgb48(65535, 65535, 0); // act - input.PackFromRgb48(expected); - actual.PackFromScaledVector4(input.ToScaledVector4()); + input.FromRgb48(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -135,8 +135,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba64(65535, 65535, 0, 65535); // act - input.PackFromRgba64(expected); - actual.PackFromScaledVector4(input.ToScaledVector4()); + input.FromRgba64(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs index 4245fcf381..6d45606bf3 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act var pixel = default(Short4); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); ulong actual = pixel.PackedValue; // assert @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(20, 38, 0, 255); // act - short4.PackFromRgba32(expected); + short4.FromRgba32(expected); actual = short4.ToRgba32(); // assert @@ -123,8 +123,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Bgra32(20, 38, 0, 255); // act - short4.PackFromBgra32(expected); - actual.PackFromRgba32(short4.ToRgba32()); + short4.FromBgra32(expected); + actual.FromRgba32(short4.ToRgba32()); // assert Assert.Equal(expected, actual); @@ -139,8 +139,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Argb32(20, 38, 0, 255); // act - short4.PackFromArgb32(expected); - actual.PackFromRgba32(short4.ToRgba32()); + short4.FromArgb32(expected); + actual.FromRgba32(short4.ToRgba32()); // assert Assert.Equal(expected, actual); @@ -155,8 +155,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgb48(65535, 0, 65535); // act - input.PackFromRgb48(expected); - actual.PackFromScaledVector4(input.ToScaledVector4()); + input.FromRgb48(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -171,8 +171,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba64(65535, 0, 65535, 0); // act - input.PackFromRgba64(expected); - actual.PackFromScaledVector4(input.ToScaledVector4()); + input.FromRgba64(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs index 97ed30b997..d68c37a768 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Tests { Image image = base.GetImage(); TPixel color = default(TPixel); - color.PackFromRgba32(new Rgba32(this.r, this.g, this.b, this.a)); + color.FromRgba32(new Rgba32(this.r, this.g, this.b, this.a)); image.Mutate(x => x.Fill(color)); return image; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs index 71ae60fabc..cc09dc0573 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs @@ -163,20 +163,20 @@ namespace SixLabors.ImageSharp.Tests { blue.W = red.W = green.W = (float)x / (float)right; - c.PackFromVector4(red); + c.FromVector4(red); int topBand = top; for (int y = topBand; y < top + height; y++) { pixels[x, y] = c; } topBand = topBand + height; - c.PackFromVector4(green); + c.FromVector4(green); for (int y = topBand; y < topBand + height; y++) { pixels[x, y] = c; } topBand = topBand + height; - c.PackFromVector4(blue); + c.FromVector4(blue); for (int y = topBand; y < bottom; y++) { pixels[x, y] = c; @@ -207,7 +207,7 @@ namespace SixLabors.ImageSharp.Tests t.PackedValue += stepsPerPixel; Vector4 v = t.ToVector4(); //v.W = (x - left) / (float)left; - c.PackFromVector4(v); + c.FromVector4(v); pixels[x, y] = c; } } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index 70b630adf1..c91ef56a1a 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -284,7 +284,7 @@ namespace SixLabors.ImageSharp.Tests { TPixel pixel = img[x, y]; Rgba64 rgbaPixel = default; - rgbaPixel.PackFromScaledVector4(pixel.ToScaledVector4()); + rgbaPixel.FromScaledVector4(pixel.ToScaledVector4()); ushort change = (ushort)Math.Round((perChannelChange / 255F) * 65535F); if (rgbaPixel.R + perChannelChange <= 255) @@ -323,7 +323,7 @@ namespace SixLabors.ImageSharp.Tests rgbaPixel.A -= perChannelChange; } - pixel.PackFromRgba64(rgbaPixel); + pixel.FromRgba64(rgbaPixel); img[x, y] = pixel; } } diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index 2384333bfb..9255634b2f 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -678,7 +678,7 @@ namespace SixLabors.ImageSharp.Tests { float value = bufferSpan[i] * scale; var v = new Vector4(value, value, value, 1f); - pixels[i].PackFromVector4(v); + pixels[i].FromVector4(v); } return image; diff --git a/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs b/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs index 7ce892edb3..e998ccd3dc 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities public TPixel AsPixel() { TPixel pix = default(TPixel); - pix.PackFromVector4(new System.Numerics.Vector4(this.Red, this.Green, this.Blue, this.Alpha)); + pix.FromVector4(new System.Numerics.Vector4(this.Red, this.Green, this.Blue, this.Alpha)); return pix; } diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs index 655f5b032c..301d0cebe6 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Tests v /= 10; var color = default(TPixel); - color.PackFromVector4(v); + color.FromVector4(v); pixels[i, j] = color; } From 8ebe390c32e8360f49fbb368699c3c0567a1a05f Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 13:54:25 +0200 Subject: [PATCH 198/381] Rename PackFrom*** -> From***: - in PixelOperations - in T4 templates - in tests --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 4 +- .../Decoder/JpegImagePostProcessor.cs | 2 +- .../Formats/Png/PngScanlineProcessor.cs | 4 +- .../PixelFormats/NamedColors{TPixel}.cs | 2 +- .../DefaultPixelBlenders.Generated.cs | 118 +--------- .../DefaultPixelBlenders.Generated.tt | 214 +++++++++--------- .../PorterDuffFunctions.Generated.tt | 2 +- .../PixelFormats/PixelBlender{TPixel}.cs | 4 +- .../Argb32.PixelOperations.Generated.cs | 2 +- .../Argb32.PixelOperations.Generated.tt | 4 +- .../Bgr24.PixelOperations.Generated.cs | 2 +- .../Bgr24.PixelOperations.Generated.tt | 4 +- .../Bgra32.PixelOperations.Generated.cs | 2 +- .../Bgra32.PixelOperations.Generated.tt | 4 +- .../Gray16.PixelOperations.Generated.cs | 2 +- .../Gray16.PixelOperations.Generated.tt | 4 +- .../Gray8.PixelOperations.Generated.cs | 2 +- .../Gray8.PixelOperations.Generated.tt | 4 +- .../Rgb24.PixelOperations.Generated.cs | 2 +- .../Rgb24.PixelOperations.Generated.tt | 4 +- .../Rgb48.PixelOperations.Generated.cs | 2 +- .../Rgb48.PixelOperations.Generated.tt | 4 +- .../Rgba32.PixelOperations.Generated.cs | 2 +- .../Rgba32.PixelOperations.Generated.tt | 4 +- .../Rgba64.PixelOperations.Generated.cs | 2 +- .../Rgba64.PixelOperations.Generated.tt | 4 +- .../Rgba32.PixelOperations.cs | 6 +- .../RgbaVector.PixelOperations.cs | 2 +- .../PixelOperations{TPixel}.Generated.cs | 82 +++---- .../PixelOperations{TPixel}.Generated.tt | 42 ++-- .../PixelFormats/PixelOperations{TPixel}.cs | 24 +- .../Convolution/Convolution2DProcessor.cs | 2 +- .../Convolution/Convolution2PassProcessor.cs | 2 +- .../Convolution/ConvolutionProcessor.cs | 2 +- .../Processors/Transforms/ResizeProcessor.cs | 2 +- .../Color/Bulk/PackFromVector4.cs | 4 +- .../Color/Bulk/PackFromXyzw.cs | 4 +- .../PixelBlenders/PorterDuffBulkVsPixel.cs | 2 +- tests/ImageSharp.Tests/Issues/Issue594.cs | 24 +- .../PixelFormats/Alpha8Tests.cs | 2 +- .../PixelFormats/Argb32Tests.cs | 2 +- .../PixelFormats/Bgr24Tests.cs | 4 +- .../PixelFormats/Bgr565Tests.cs | 2 +- .../PixelFormats/Bgra32Tests.cs | 4 +- .../PixelFormats/Bgra4444Tests.cs | 2 +- .../PixelFormats/Bgra5551Tests.cs | 2 +- .../PixelFormats/Byte4Tests.cs | 2 +- .../PixelFormats/Gray16Tests.cs | 6 +- .../PixelFormats/Gray8Tests.cs | 6 +- .../PixelFormats/HalfSingleTests.cs | 2 +- .../PixelFormats/HalfVector2Tests.cs | 2 +- .../PixelFormats/HalfVector4Tests.cs | 2 +- .../PixelFormats/NormalizedByte2Tests.cs | 2 +- .../PixelFormats/NormalizedByte4Tests.cs | 2 +- .../PixelFormats/NormalizedShort2Tests.cs | 2 +- .../PixelFormats/NormalizedShort4Tests.cs | 2 +- .../PixelFormats/PixelOperationsTests.cs | 52 ++--- .../PixelFormats/Rg32Tests.cs | 2 +- .../PixelFormats/Rgb24Tests.cs | 4 +- .../PixelFormats/Rgb48Tests.cs | 2 +- .../PixelFormats/Rgba1010102Tests.cs | 2 +- .../PixelFormats/Rgba32Tests.cs | 12 +- .../PixelFormats/Rgba64Tests.cs | 2 +- .../PixelFormats/RgbaVectorTests.cs | 4 +- .../PixelFormats/Short2Tests.cs | 8 +- .../PixelFormats/Short4Tests.cs | 12 +- .../ReferenceCodecs/MagickReferenceDecoder.cs | 4 +- .../ReferenceCodecs/SystemDrawingBridge.cs | 4 +- .../TestUtilities/TestImageExtensions.cs | 2 +- 69 files changed, 321 insertions(+), 437 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 8ebfb37ebd..77cd322221 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -436,7 +436,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.stream.Read(row); int newY = Invert(y, height, inverted); Span pixelSpan = pixels.GetRowSpan(newY); - PixelOperations.Instance.PackFromBgr24Bytes(row.GetSpan(), pixelSpan, width); + PixelOperations.Instance.FromBgr24Bytes(row.GetSpan(), pixelSpan, width); } } } @@ -461,7 +461,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.stream.Read(row); int newY = Invert(y, height, inverted); Span pixelSpan = pixels.GetRowSpan(newY); - PixelOperations.Instance.PackFromBgra32Bytes(row.GetSpan(), pixelSpan, width); + PixelOperations.Instance.FromBgra32Bytes(row.GetSpan(), pixelSpan, width); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs index 94382553ca..eb618dff0e 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs @@ -159,7 +159,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder Span destRow = destination.GetPixelRowSpan(yy); - PixelOperations.Instance.PackFromVector4(this.rgbaBuffer.GetSpan(), destRow, destination.Width); + PixelOperations.Instance.FromVector4(this.rgbaBuffer.GetSpan(), destRow, destination.Width); } } } diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index b4e5f201f0..e4a2562e65 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -377,7 +377,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - PixelOperations.Instance.PackFromRgb24Bytes(scanlineSpan, rowSpan, header.Width); + PixelOperations.Instance.FromRgb24Bytes(scanlineSpan, rowSpan, header.Width); } return; @@ -526,7 +526,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - PixelOperations.Instance.PackFromRgba32Bytes(scanlineSpan, rowSpan, header.Width); + PixelOperations.Instance.FromRgba32Bytes(scanlineSpan, rowSpan, header.Width); } } diff --git a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs index 0f42e182c5..1923faa1fc 100644 --- a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs @@ -739,7 +739,7 @@ namespace SixLabors.ImageSharp.PixelFormats var safe = new TPixel[constants.Length + 1]; Span constantsBytes = MemoryMarshal.Cast(constants.AsSpan()); - PixelOperations.Instance.PackFromRgba32Bytes(constantsBytes, safe, constants.Length); + PixelOperations.Instance.FromRgba32Bytes(constantsBytes, safe, constants.Length); return safe; } } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs index c0a38b1a33..1d3cb53afc 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs @@ -1,11 +1,4 @@ - - - - - - - -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. // @@ -33,7 +26,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders where TPixel : struct, IPixel { - internal class NormalSrc : PixelBlender { /// @@ -69,7 +61,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplySrc : PixelBlender { /// @@ -105,7 +96,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddSrc : PixelBlender { /// @@ -141,7 +131,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractSrc : PixelBlender { /// @@ -177,7 +166,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenSrc : PixelBlender { /// @@ -213,7 +201,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenSrc : PixelBlender { /// @@ -249,7 +236,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenSrc : PixelBlender { /// @@ -285,7 +271,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlaySrc : PixelBlender { /// @@ -321,7 +306,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightSrc : PixelBlender { /// @@ -357,7 +341,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalSrcAtop : PixelBlender { /// @@ -393,7 +376,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplySrcAtop : PixelBlender { /// @@ -429,7 +411,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddSrcAtop : PixelBlender { /// @@ -465,7 +446,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractSrcAtop : PixelBlender { /// @@ -501,7 +481,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenSrcAtop : PixelBlender { /// @@ -537,7 +516,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenSrcAtop : PixelBlender { /// @@ -573,7 +551,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenSrcAtop : PixelBlender { /// @@ -609,7 +586,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlaySrcAtop : PixelBlender { /// @@ -645,7 +621,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightSrcAtop : PixelBlender { /// @@ -681,7 +656,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalSrcOver : PixelBlender { /// @@ -717,7 +691,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplySrcOver : PixelBlender { /// @@ -753,7 +726,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddSrcOver : PixelBlender { /// @@ -789,7 +761,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractSrcOver : PixelBlender { /// @@ -825,7 +796,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenSrcOver : PixelBlender { /// @@ -861,7 +831,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenSrcOver : PixelBlender { /// @@ -897,7 +866,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenSrcOver : PixelBlender { /// @@ -933,7 +901,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlaySrcOver : PixelBlender { /// @@ -969,7 +936,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightSrcOver : PixelBlender { /// @@ -1005,7 +971,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalSrcIn : PixelBlender { /// @@ -1041,7 +1006,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplySrcIn : PixelBlender { /// @@ -1077,7 +1041,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddSrcIn : PixelBlender { /// @@ -1113,7 +1076,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractSrcIn : PixelBlender { /// @@ -1149,7 +1111,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenSrcIn : PixelBlender { /// @@ -1185,7 +1146,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenSrcIn : PixelBlender { /// @@ -1221,7 +1181,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenSrcIn : PixelBlender { /// @@ -1257,7 +1216,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlaySrcIn : PixelBlender { /// @@ -1293,7 +1251,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightSrcIn : PixelBlender { /// @@ -1329,7 +1286,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalSrcOut : PixelBlender { /// @@ -1365,7 +1321,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplySrcOut : PixelBlender { /// @@ -1401,7 +1356,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddSrcOut : PixelBlender { /// @@ -1437,7 +1391,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractSrcOut : PixelBlender { /// @@ -1473,7 +1426,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenSrcOut : PixelBlender { /// @@ -1509,7 +1461,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenSrcOut : PixelBlender { /// @@ -1545,7 +1496,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenSrcOut : PixelBlender { /// @@ -1581,7 +1531,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlaySrcOut : PixelBlender { /// @@ -1617,7 +1566,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightSrcOut : PixelBlender { /// @@ -1653,7 +1601,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalDest : PixelBlender { /// @@ -1689,7 +1636,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplyDest : PixelBlender { /// @@ -1725,7 +1671,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddDest : PixelBlender { /// @@ -1761,7 +1706,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractDest : PixelBlender { /// @@ -1797,7 +1741,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenDest : PixelBlender { /// @@ -1833,7 +1776,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenDest : PixelBlender { /// @@ -1869,7 +1811,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenDest : PixelBlender { /// @@ -1905,7 +1846,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlayDest : PixelBlender { /// @@ -1941,7 +1881,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightDest : PixelBlender { /// @@ -1977,7 +1916,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalDestAtop : PixelBlender { /// @@ -2013,7 +1951,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplyDestAtop : PixelBlender { /// @@ -2049,7 +1986,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddDestAtop : PixelBlender { /// @@ -2085,7 +2021,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractDestAtop : PixelBlender { /// @@ -2121,7 +2056,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenDestAtop : PixelBlender { /// @@ -2157,7 +2091,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenDestAtop : PixelBlender { /// @@ -2193,7 +2126,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenDestAtop : PixelBlender { /// @@ -2229,7 +2161,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlayDestAtop : PixelBlender { /// @@ -2265,7 +2196,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightDestAtop : PixelBlender { /// @@ -2301,7 +2231,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalDestOver : PixelBlender { /// @@ -2337,7 +2266,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplyDestOver : PixelBlender { /// @@ -2373,7 +2301,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddDestOver : PixelBlender { /// @@ -2409,7 +2336,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractDestOver : PixelBlender { /// @@ -2445,7 +2371,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenDestOver : PixelBlender { /// @@ -2481,7 +2406,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenDestOver : PixelBlender { /// @@ -2517,7 +2441,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenDestOver : PixelBlender { /// @@ -2553,7 +2476,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlayDestOver : PixelBlender { /// @@ -2589,7 +2511,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightDestOver : PixelBlender { /// @@ -2625,7 +2546,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalDestIn : PixelBlender { /// @@ -2661,7 +2581,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplyDestIn : PixelBlender { /// @@ -2697,7 +2616,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddDestIn : PixelBlender { /// @@ -2733,7 +2651,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractDestIn : PixelBlender { /// @@ -2769,7 +2686,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenDestIn : PixelBlender { /// @@ -2805,7 +2721,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenDestIn : PixelBlender { /// @@ -2841,7 +2756,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenDestIn : PixelBlender { /// @@ -2877,7 +2791,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlayDestIn : PixelBlender { /// @@ -2913,7 +2826,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightDestIn : PixelBlender { /// @@ -2949,7 +2861,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalDestOut : PixelBlender { /// @@ -2985,7 +2896,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplyDestOut : PixelBlender { /// @@ -3021,7 +2931,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddDestOut : PixelBlender { /// @@ -3057,7 +2966,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractDestOut : PixelBlender { /// @@ -3093,7 +3001,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenDestOut : PixelBlender { /// @@ -3129,7 +3036,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenDestOut : PixelBlender { /// @@ -3165,7 +3071,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenDestOut : PixelBlender { /// @@ -3201,7 +3106,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlayDestOut : PixelBlender { /// @@ -3237,7 +3141,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightDestOut : PixelBlender { /// @@ -3273,7 +3176,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalClear : PixelBlender { /// @@ -3309,7 +3211,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplyClear : PixelBlender { /// @@ -3345,7 +3246,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddClear : PixelBlender { /// @@ -3381,7 +3281,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractClear : PixelBlender { /// @@ -3417,7 +3316,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenClear : PixelBlender { /// @@ -3453,7 +3351,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenClear : PixelBlender { /// @@ -3489,7 +3386,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenClear : PixelBlender { /// @@ -3525,7 +3421,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlayClear : PixelBlender { /// @@ -3561,7 +3456,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightClear : PixelBlender { /// @@ -3597,7 +3491,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalXor : PixelBlender { /// @@ -3633,7 +3526,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplyXor : PixelBlender { /// @@ -3669,7 +3561,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddXor : PixelBlender { /// @@ -3705,7 +3596,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractXor : PixelBlender { /// @@ -3741,7 +3631,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenXor : PixelBlender { /// @@ -3777,7 +3666,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenXor : PixelBlender { /// @@ -3813,7 +3701,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenXor : PixelBlender { /// @@ -3849,7 +3736,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlayXor : PixelBlender { /// @@ -3885,7 +3771,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightXor : PixelBlender { /// @@ -3921,6 +3806,5 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - } } \ 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 f776da7a02..b7ea7a9d43 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt @@ -1,114 +1,114 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> -<#@ output extension=".cs" #> -// 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. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +// 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 - { - -<# - string[] composers = new []{ - "Src", - "SrcAtop", - "SrcOver", - "SrcIn", - "SrcOut", - "Dest", - "DestAtop", - "DestOver", - "DestIn", - "DestOut", - "Clear", - "Xor", - }; - - string[] blenders = new []{ - "Normal", - "Multiply", - "Add", - "Subtract", - "Screen", - "Darken", - "Lighten", - "Overlay", - "HardLight" - }; - - foreach(var composer in composers) { - foreach(var blender in blenders) { - - string blender_composer= $"{blender}{composer}"; - -#> - internal class <#= blender_composer#> : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static <#=blender_composer#> Instance { get; } = new <#=blender_composer#>(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { +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 + { + +<# + string[] composers = new []{ + "Src", + "SrcAtop", + "SrcOver", + "SrcIn", + "SrcOut", + "Dest", + "DestAtop", + "DestOver", + "DestIn", + "DestOut", + "Clear", + "Xor", + }; + + string[] blenders = new []{ + "Normal", + "Multiply", + "Add", + "Subtract", + "Screen", + "Darken", + "Lighten", + "Overlay", + "HardLight" + }; + + foreach(var composer in composers) { + foreach(var blender in blenders) { + + string blender_composer= $"{blender}{composer}"; + +#> + internal class <#= blender_composer#> : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static <#=blender_composer#> Instance { get; } = new <#=blender_composer#>(); + + /// + 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))); - 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); - } - } - - /// - 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].Clamp(0, 1)); - } - } - } - -<# - } - } - -#> - } + dest.FromScaledVector4(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); + } + } + + /// + 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].Clamp(0, 1)); + } + } + } + +<# + } + } + +#> + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt index 73c835e606..e21a78031f 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt @@ -133,7 +133,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(<#=blender#><#=composer#>(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(<#=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 cca4a10179..48a83335a0 100644 --- a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs @@ -98,7 +98,7 @@ namespace SixLabors.ImageSharp.PixelFormats this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); - PixelOperations.Instance.PackFromScaledVector4(destinationSpan, destination, destination.Length); + PixelOperations.Instance.FromScaledVector4(destinationSpan, destination, destination.Length); } } @@ -132,7 +132,7 @@ namespace SixLabors.ImageSharp.PixelFormats this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); - PixelOperations.Instance.PackFromScaledVector4(destinationSpan, destination, destination.Length); + PixelOperations.Instance.FromScaledVector4(destinationSpan, destination, destination.Length); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs index 2fa7df94e8..16121d62d8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) + internal override void FromArgb32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt index f35adee022..f903846719 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt @@ -26,7 +26,7 @@ ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromArgb32(sp); + dp.FromArgb32(sp); } } <# @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) + internal override void FromArgb32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs index 950c6d5d90..cbfbe70991 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) + internal override void FromBgr24(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt index 76163549b0..0f7bd838ff 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt @@ -26,7 +26,7 @@ ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgr24(sp); + dp.FromBgr24(sp); } } <# @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) + internal override void FromBgr24(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs index f29fa78ec3..edd702e0e0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) + internal override void FromBgra32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt index 4c2925d18f..4c4e10fad0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt @@ -26,7 +26,7 @@ ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgra32(sp); + dp.FromBgra32(sp); } } <# @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) + internal override void FromBgra32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs index 1b679c50a4..ca0e1fe326 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromGray16(ReadOnlySpan source, Span destPixels, int count) + internal override void FromGray16(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt index b900e343a7..1e500dac54 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt @@ -26,7 +26,7 @@ ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray16(sp); + dp.FromGray16(sp); } } <# @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromGray16(ReadOnlySpan source, Span destPixels, int count) + internal override void FromGray16(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs index 1be3cc4687..6950c337d6 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromGray8(ReadOnlySpan source, Span destPixels, int count) + internal override void FromGray8(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt index 4590420e57..7c6e2f7675 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt @@ -26,7 +26,7 @@ ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray8(sp); + dp.FromGray8(sp); } } <# @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromGray8(ReadOnlySpan source, Span destPixels, int count) + internal override void FromGray8(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs index c6a7c70694..53234cd66e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgb24(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt index 6a10b401f4..b98e1e4c7c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt @@ -26,7 +26,7 @@ ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb24(sp); + dp.FromRgb24(sp); } } <# @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgb24(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs index dcc0f38024..61d13978ab 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromRgb48(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgb48(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt index e38c85bf62..2ff3125b4c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt @@ -26,7 +26,7 @@ ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb48(sp); + dp.FromRgb48(sp); } } <# @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromRgb48(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgb48(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs index 63dbc7405d..ae2ffd6888 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal partial class PixelOperations { /// - internal override void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgba32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt index 23d0be740e..fb8d6db349 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt @@ -26,7 +26,7 @@ ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba32(sp); + dp.FromRgba32(sp); } } <# @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal partial class PixelOperations { /// - internal override void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgba32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs index f92fe8ec70..252068828e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromRgba64(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgba64(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt index e998341570..626f2316d3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt @@ -26,7 +26,7 @@ ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba64(sp); + dp.FromRgba64(sp); } } <# @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromRgba64(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgba64(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs index 13432e58f8..4da9f101bc 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void PackFromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) + internal override void FromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) { GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); @@ -52,9 +52,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void PackFromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) + internal override void FromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) { - this.PackFromVector4(sourceVectors, destinationColors, count); + this.FromVector4(sourceVectors, destinationColors, count); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs index aae6ee6940..ae64ed4de3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) + internal override void FromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) { GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs index 2708af0749..f1d426389b 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs @@ -1,13 +1,13 @@ // 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.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - public partial class PixelOperations { /// @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromArgb32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -33,16 +33,16 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// 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 PackFromArgb32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromArgb32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromArgb32(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromArgb32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } /// @@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromBgr24(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -103,16 +103,16 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// 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 PackFromBgr24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromBgr24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromBgr24(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromBgr24(MemoryMarshal.Cast(sourceBytes), destPixels, count); } /// @@ -156,7 +156,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromBgra32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -173,16 +173,16 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// 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 PackFromBgra32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromBgra32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromBgra32(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromBgra32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } /// @@ -226,7 +226,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromGray8(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromGray8(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -243,16 +243,16 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// 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 PackFromGray8Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromGray8Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromGray8(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromGray8(MemoryMarshal.Cast(sourceBytes), destPixels, count); } /// @@ -296,7 +296,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromGray16(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromGray16(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -313,16 +313,16 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// 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 PackFromGray16Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromGray16Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromGray16(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromGray16(MemoryMarshal.Cast(sourceBytes), destPixels, count); } /// @@ -366,7 +366,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromRgb24(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -383,16 +383,16 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// 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 PackFromRgb24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromRgb24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromRgb24(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromRgb24(MemoryMarshal.Cast(sourceBytes), destPixels, count); } /// @@ -436,7 +436,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromRgba32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -453,16 +453,16 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// 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 PackFromRgba32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromRgba32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromRgba32(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromRgba32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } /// @@ -506,7 +506,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromRgb48(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromRgb48(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -523,16 +523,16 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// 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 PackFromRgb48Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromRgb48Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromRgb48(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromRgb48(MemoryMarshal.Cast(sourceBytes), destPixels, count); } /// @@ -576,7 +576,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromRgba64(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromRgba64(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -593,16 +593,16 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// 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 PackFromRgba64Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromRgba64Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromRgba64(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromRgba64(MemoryMarshal.Cast(sourceBytes), destPixels, count); } /// diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt index 913dabb087..723b0358fe 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt @@ -11,7 +11,7 @@ <#@ output extension=".cs" #> <# - void GeneratePackFromMethods(string pixelType) + void GenerateFromMethods(string pixelType) { #> @@ -21,7 +21,7 @@ /// 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) + internal virtual void From<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -33,21 +33,21 @@ ref <#=pixelType#> sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFrom<#=pixelType#>(sp); + dp.From<#=pixelType#>(sp); } } /// - /// A helper for that expects a byte span. + /// 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) + internal void From<#=pixelType#>Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFrom<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); + this.From<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); } <# @@ -74,7 +74,7 @@ ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromScaledVector4(sp.ToScaledVector4()); + dp.FromScaledVector4(sp.ToScaledVector4()); } } @@ -96,42 +96,42 @@ #> // 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.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - public partial class PixelOperations {<# - GeneratePackFromMethods("Argb32"); + GenerateFromMethods("Argb32"); GenerateToDestFormatMethods("Argb32"); - GeneratePackFromMethods("Bgr24"); + GenerateFromMethods("Bgr24"); GenerateToDestFormatMethods("Bgr24"); - GeneratePackFromMethods("Bgra32"); + GenerateFromMethods("Bgra32"); GenerateToDestFormatMethods("Bgra32"); - GeneratePackFromMethods("Gray8"); + GenerateFromMethods("Gray8"); GenerateToDestFormatMethods("Gray8"); - GeneratePackFromMethods("Gray16"); + GenerateFromMethods("Gray16"); GenerateToDestFormatMethods("Gray16"); - GeneratePackFromMethods("Rgb24"); + GenerateFromMethods("Rgb24"); GenerateToDestFormatMethods("Rgb24"); - GeneratePackFromMethods("Rgba32"); + GenerateFromMethods("Rgba32"); GenerateToDestFormatMethods("Rgba32"); - GeneratePackFromMethods("Rgb48"); + GenerateFromMethods("Rgb48"); GenerateToDestFormatMethods("Rgb48"); - GeneratePackFromMethods("Rgba64"); + GenerateFromMethods("Rgba64"); GenerateToDestFormatMethods("Rgba64"); #> } diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 926b234d75..af7690c62d 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The to the source vectors. /// The to the destination colors. /// The number of pixels to convert. - internal virtual void PackFromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) + internal virtual void FromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) { GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The to the source vectors. /// The to the destination colors. /// The number of pixels to convert. - internal virtual void PackFromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) + internal virtual void FromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) { GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); @@ -108,12 +108,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Performs a bulk conversion of a collection of one pixel format into another. /// - /// The pixel format. + /// The pixel format. /// The to the source colors. /// The to the destination colors. /// The number of pixels to convert. - internal virtual void To(ReadOnlySpan sourceColors, Span destinationColors, int count) - where TPixel2 : struct, IPixel + internal virtual void To(ReadOnlySpan sourceColors, Span destinationColors, int count) + where TDestinationPixel : struct, IPixel { GuardSpans(sourceColors, nameof(sourceColors), destinationColors, nameof(destinationColors), count); @@ -121,11 +121,11 @@ namespace SixLabors.ImageSharp.PixelFormats // Gray8 and Gray16 are special implementations of IPixel in that they do not conform to the // standard RGBA colorspace format and must be converted from RGBA using the special ITU BT709 alogrithm. - // One of the requirements of PackFromScaledVector4/ToScaledVector4 is that it unaware of this and + // One of the requirements of FromScaledVector4/ToScaledVector4 is that it unaware of this and // packs/unpacks the pixel without and conversion so we employ custom methods do do this. - if (typeof(TPixel2).Equals(typeof(Gray16))) + if (typeof(TDestinationPixel) == typeof(Gray16)) { - ref Gray16 gray16Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(destinationColors)); + ref Gray16 gray16Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(destinationColors)); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); @@ -136,9 +136,9 @@ namespace SixLabors.ImageSharp.PixelFormats return; } - if (typeof(TPixel2).Equals(typeof(Gray8))) + if (typeof(TDestinationPixel) == typeof(Gray8)) { - ref Gray8 gray8Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(destinationColors)); + ref Gray8 gray8Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(destinationColors)); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); @@ -150,11 +150,11 @@ namespace SixLabors.ImageSharp.PixelFormats } // Normal converson - ref TPixel2 destRef = ref MemoryMarshal.GetReference(destinationColors); + ref TDestinationPixel destRef = ref MemoryMarshal.GetReference(destinationColors); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); - ref TPixel2 dp = ref Unsafe.Add(ref destRef, i); + ref TDestinationPixel dp = ref Unsafe.Add(ref destRef, i); dp.FromScaledVector4(sp.ToScaledVector4()); } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs index 0669a12470..df4df64cad 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs @@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution DenseMatrixUtils.Convolve2D(in matrixY, in matrixX, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.PackFromVector4(vectorSpan, targetRowSpan, length); + PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan, length); } }); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs index 1f47649e6f..03447531ef 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution DenseMatrixUtils.Convolve(in matrix, sourcePixels, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.PackFromVector4(vectorSpan, targetRowSpan, length); + PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan, length); } }); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs index d2f3f8fc58..a42b777feb 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution DenseMatrixUtils.Convolve(in matrix, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.PackFromVector4(vectorSpan, targetRowSpan, length); + PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan, length); } }); diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 812c0578b2..5bd61aab19 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -309,7 +309,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } Span targetRowSpan = destination.GetPixelRowSpan(y); - PixelOperations.Instance.PackFromVector4(tempRowSpan, targetRowSpan, tempRowSpan.Length); + PixelOperations.Instance.FromVector4(tempRowSpan, targetRowSpan, tempRowSpan.Length); } }); } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index e39c464f1a..3839bf58ee 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -59,13 +59,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Benchmark] public void PixelOperations_Base() { - new PixelOperations().PackFromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + new PixelOperations().FromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } [Benchmark] public void PixelOperations_Specialized() { - PixelOperations.Instance.PackFromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + PixelOperations.Instance.FromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs index 5272351045..b1025e80ce 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs @@ -55,13 +55,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Benchmark] public void CommonBulk() { - new PixelOperations().PackFromRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + new PixelOperations().FromRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } [Benchmark] public void OptimizedBulk() { - PixelOperations.Instance.PackFromRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + PixelOperations.Instance.FromRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } } diff --git a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs index d9cf65d4be..46b58f369d 100644 --- a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs +++ b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs @@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Benchmarks destinationSpan[i] = PorterDuffFunctions.NormalSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + PixelOperations.Instance.FromVector4(destinationSpan, destination, destination.Length); } } diff --git a/tests/ImageSharp.Tests/Issues/Issue594.cs b/tests/ImageSharp.Tests/Issues/Issue594.cs index 48e355ea78..927f0a5edc 100644 --- a/tests/ImageSharp.Tests/Issues/Issue594.cs +++ b/tests/ImageSharp.Tests/Issues/Issue594.cs @@ -31,7 +31,7 @@ namespace SixLabors.ImageSharp.Tests.Issues Assert.Equal(0, scaled.Z); Assert.Equal(0, scaled.W); - // Test PackFromScaledVector4. + // Test FromScaledVector4. var pixel = default(NormalizedByte4); pixel.FromScaledVector4(scaled); Assert.Equal(0x81818181, pixel.PackedValue); @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.Tests.Issues // http://community.monogame.net/t/normalizedbyte4-texture2d-gives-different-results-from-xna/8012/8 //var r = default(NormalizedByte4); - //r.PackFromRgba32(new Rgba32(9, 115, 202, 127)); + //r.FromRgba32(new Rgba32(9, 115, 202, 127)); //r.ToRgba32(ref rgba); //Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); @@ -80,12 +80,12 @@ namespace SixLabors.ImageSharp.Tests.Issues //Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); //r = default(NormalizedByte4); - //r.PackFromArgb32(new Argb32(9, 115, 202, 127)); + //r.FromArgb32(new Argb32(9, 115, 202, 127)); //r.ToArgb32(ref argb); //Assert.Equal(argb, new Argb32(9, 115, 202, 127)); //r = default(NormalizedByte4); - //r.PackFromBgra32(new Bgra32(9, 115, 202, 127)); + //r.FromBgra32(new Bgra32(9, 115, 202, 127)); //r.ToBgra32(ref bgra); //Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); } @@ -114,7 +114,7 @@ namespace SixLabors.ImageSharp.Tests.Issues Assert.Equal(1, scaled.Z); Assert.Equal(1, scaled.W); - // Test PackFromScaledVector4. + // Test FromScaledVector4. var pixel = default(NormalizedShort4); pixel.FromScaledVector4(scaled); Assert.Equal((ulong)0x7FFF7FFF7FFF7FFF, pixel.PackedValue); @@ -149,17 +149,17 @@ namespace SixLabors.ImageSharp.Tests.Issues //Assert.Equal(argb, new Argb32(141, 90, 192, 39)); //var r = default(NormalizedShort4); - //r.PackFromRgba32(new Rgba32(9, 115, 202, 127)); + //r.FromRgba32(new Rgba32(9, 115, 202, 127)); //r.ToRgba32(ref rgba); //Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); //r = default(NormalizedShort4); - //r.PackFromBgra32(new Bgra32(9, 115, 202, 127)); + //r.FromBgra32(new Bgra32(9, 115, 202, 127)); //r.ToBgra32(ref bgra); //Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); //r = default(NormalizedShort4); - //r.PackFromArgb32(new Argb32(9, 115, 202, 127)); + //r.FromArgb32(new Argb32(9, 115, 202, 127)); //r.ToArgb32(ref argb); //Assert.Equal(argb, new Argb32(9, 115, 202, 127)); } @@ -190,7 +190,7 @@ namespace SixLabors.ImageSharp.Tests.Issues Assert.Equal(1, scaled.Z); Assert.Equal(1, scaled.W); - // Test PackFromScaledVector4. + // Test FromScaledVector4. var pixel = default(Short4); pixel.FromScaledVector4(scaled); Assert.Equal((ulong)0x7FFF7FFF7FFF7FFF, pixel.PackedValue); @@ -234,17 +234,17 @@ namespace SixLabors.ImageSharp.Tests.Issues //Assert.Equal(argb, new Argb32(172, 177, 243, 128)); //var r = default(Short4); - //r.PackFromRgba32(new Rgba32(20, 38, 0, 255)); + //r.FromRgba32(new Rgba32(20, 38, 0, 255)); //r.ToRgba32(ref rgba); //Assert.Equal(rgba, new Rgba32(20, 38, 0, 255)); //r = default(Short4); - //r.PackFromBgra32(new Bgra32(20, 38, 0, 255)); + //r.FromBgra32(new Bgra32(20, 38, 0, 255)); //r.ToBgra32(ref bgra); //Assert.Equal(bgra, new Bgra32(20, 38, 0, 255)); //r = default(Short4); - //r.PackFromArgb32(new Argb32(20, 38, 0, 255)); + //r.FromArgb32(new Argb32(20, 38, 0, 255)); //r.ToArgb32(ref argb); //Assert.Equal(argb, new Argb32(20, 38, 0, 255)); } diff --git a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs index 067c1a9779..148b928fac 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Alpha8_PackFromScaledVector4() + public void Alpha8_FromScaledVector4() { // Arrange Alpha8 alpha = default; diff --git a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs index 31b9a53a04..b9f7414900 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Argb32_PackFromScaledVector4() + public void Argb32_FromScaledVector4() { // arrange Vector4 scaled = new Argb32(Vector4.One).ToScaledVector4(); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs index ce284f4201..2295fbe56f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs @@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] - public void PackFromRgba32() + public void FromRgba32() { var rgb = default(Bgr24); rgb.FromRgba32(new Rgba32(1, 2, 3, 4)); @@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats a / 255f); [Fact] - public void PackFromVector4() + public void FromVector4() { var rgb = default(Bgr24); rgb.FromVector4(Vec(1, 2, 3, 4)); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs index 5033788b84..967e358e1e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Bgr565_PackFromScaledVector4() + public void Bgr565_FromScaledVector4() { // arrange Vector4 scaled = new Bgr565(Vector3.One).ToScaledVector4(); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs index 93993cc399..a5c53ed8b0 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs @@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] - public void PackFromRgba32() + public void FromRgba32() { var rgb = default(Rgb24); rgb.FromRgba32(new Rgba32(1, 2, 3, 4)); @@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats a / 255f); [Fact] - public void PackFromVector4() + public void FromVector4() { var c = default(Bgra32); c.FromVector4(Vec(1, 2, 3, 4)); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs index 3f6b7653f4..8b56ec19fe 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Bgra4444_PackFromScaledVector4() + public void Bgra4444_FromScaledVector4() { // arrange Vector4 scaled = new Bgra4444(Vector4.One).ToScaledVector4(); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs index eaf397bb5b..76edee8a73 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Bgra5551_PackFromScaledVector4() + public void Bgra5551_FromScaledVector4() { // arrange Vector4 scaled = new Bgra5551(Vector4.One).ToScaledVector4(); diff --git a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs index c172bbdaca..8391ef25ae 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Byte4_PackFromScaledVector4() + public void Byte4_FromScaledVector4() { // arrange Vector4 scaled = new Byte4(Vector4.One * 255).ToScaledVector4(); diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs index 69a44a9bbf..220ca2899a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats => Assert.Equal(input, new Gray16(input).PackedValue); [Fact] - public void Gray16_PackFromScaledVector4() + public void Gray16_FromScaledVector4() { // Arrange Gray16 gray = default; @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Gray16_PackFromVector4() + public void Gray16_FromVector4() { // Arrange Gray16 gray = default; @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Gray16_PackFromRgba32() + public void Gray16_FromRgba32() { // Arrange Gray16 gray = default; diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs index 7886be9e02..988002c099 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats => Assert.Equal(input, new Gray8(input).PackedValue); [Fact] - public void Gray8_PackFromScaledVector4() + public void Gray8_FromScaledVector4() { // Arrange Gray8 gray = default; @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Gray8_PackFromVector4() + public void Gray8_FromVector4() { // Arrange Gray8 gray = default; @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Gray8_PackFromRgba32() + public void Gray8_FromRgba32() { // Arrange Gray8 gray = default; diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs index a503db01cb..85a3b8b320 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void HalfSingle_PackFromScaledVector4() + public void HalfSingle_FromScaledVector4() { // arrange Vector4 scaled = new HalfSingle(-1F).ToScaledVector4(); diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs index a892b84137..ccdd23e8fb 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs @@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void HalfVector2_PackFromScaledVector4() + public void HalfVector2_FromScaledVector4() { // arrange Vector4 scaled = new HalfVector2(Vector2.One).ToScaledVector4(); diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs index 02a05a76f9..c61dd97d2a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void HalfVector4_PackFromScaledVector4() + public void HalfVector4_FromScaledVector4() { // arrange var halfVector4 = default(HalfVector4); diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs index faaeae6cc1..506ebe0fe0 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void NormalizedByte2_PackFromScaledVector4() + public void NormalizedByte2_FromScaledVector4() { // arrange Vector4 scaled = new NormalizedByte2(-Vector2.One).ToScaledVector4(); diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs index 4465fbaed3..19a49e5d8a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void NormalizedByte4_PackFromScaledVector4() + public void NormalizedByte4_FromScaledVector4() { // arrange var pixel = default(NormalizedByte4); diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs index 4f66d04e35..216ed4ad75 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs @@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void NormalizedShort2_PackFromScaledVector4() + public void NormalizedShort2_FromScaledVector4() { // arrange Vector4 scaled = new NormalizedShort2(-Vector2.One).ToScaledVector4(); diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs index b93960dbf8..d06d46d06f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void NormalizedShort4_PackFromScaledVector4() + public void NormalizedShort4_FromScaledVector4() { // arrange var pixel = default(NormalizedShort4); diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index ef57458c96..958c4744ad 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromGray8Bytes(int count) + public void FromGray8Bytes(int count) { byte[] source = CreateByteTestData(count); var expected = new Gray8[count]; @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromGray8Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromGray8Bytes(s, d.GetSpan(), count) ); } @@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromGray16Bytes(int count) + public void FromGray16Bytes(int count) { byte[] source = CreateByteTestData(count * 2); Span sourceSpan = source.AsSpan(); @@ -123,7 +123,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromGray16Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromGray16Bytes(s, d.GetSpan(), count) ); } @@ -164,7 +164,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromGray8Bytes(int count) + public void FromGray8Bytes(int count) { byte[] source = CreateByteTestData(count); var expected = new Gray16[count]; @@ -177,7 +177,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromGray8Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromGray8Bytes(s, d.GetSpan(), count) ); } @@ -204,7 +204,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromGray16Bytes(int count) + public void FromGray16Bytes(int count) { byte[] source = CreateByteTestData(count * 2); Span sourceSpan = source.AsSpan(); @@ -219,7 +219,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromGray16Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromGray16Bytes(s, d.GetSpan(), count) ); } @@ -359,7 +359,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromVector4(int count) + public void FromVector4(int count) { Vector4[] source = CreateVector4TestData(count); TPixel[] expected = CreateExpectedPixelData(source); @@ -367,13 +367,13 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromVector4(s, d.GetSpan(), count) + (s, d) => Operations.FromVector4(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromScaledVector4(int count) + public void FromScaledVector4(int count) { Vector4[] source = CreateVector4TestData(count); TPixel[] expected = CreateScaledExpectedPixelData(source); @@ -381,7 +381,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromScaledVector4(s, d.GetSpan(), count) + (s, d) => Operations.FromScaledVector4(s, d.GetSpan(), count) ); } @@ -437,7 +437,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromArgb32Bytes(int count) + public void FromArgb32Bytes(int count) { byte[] source = CreateByteTestData(count * 4); var expected = new TPixel[count]; @@ -452,7 +452,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromArgb32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromArgb32Bytes(s, d.GetSpan(), count) ); } @@ -484,7 +484,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromBgr24Bytes(int count) + public void FromBgr24Bytes(int count) { byte[] source = CreateByteTestData(count * 3); var expected = new TPixel[count]; @@ -499,7 +499,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromBgr24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromBgr24Bytes(s, d.GetSpan(), count) ); } @@ -529,7 +529,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromBgra32Bytes(int count) + public void FromBgra32Bytes(int count) { byte[] source = CreateByteTestData(count * 4); var expected = new TPixel[count]; @@ -544,7 +544,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromBgra32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromBgra32Bytes(s, d.GetSpan(), count) ); } @@ -575,7 +575,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgb24Bytes(int count) + public void FromRgb24Bytes(int count) { byte[] source = CreateByteTestData(count * 3); var expected = new TPixel[count]; @@ -590,7 +590,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromRgb24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgb24Bytes(s, d.GetSpan(), count) ); } @@ -620,7 +620,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgba32Bytes(int count) + public void FromRgba32Bytes(int count) { byte[] source = CreateByteTestData(count * 4); var expected = new TPixel[count]; @@ -635,7 +635,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromRgba32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgba32Bytes(s, d.GetSpan(), count) ); } @@ -666,7 +666,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgb48Bytes(int count) + public void FromRgb48Bytes(int count) { byte[] source = CreateByteTestData(count * 6); Span sourceSpan = source.AsSpan(); @@ -681,7 +681,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromRgb48Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgb48Bytes(s, d.GetSpan(), count) ); } @@ -715,7 +715,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgba64Bytes(int count) + public void FromRgba64Bytes(int count) { byte[] source = CreateByteTestData(count * 8); Span sourceSpan = source.AsSpan(); @@ -730,7 +730,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromRgba64Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgba64Bytes(s, d.GetSpan(), count) ); } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs index d4347cae65..46e5fbc3cd 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Rg32_PackFromScaledVector4() + public void Rg32_FromScaledVector4() { // arrange var rg32 = new Rg32(Vector2.One); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs index 918a147d9e..a60509146d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void PackFromRgba32() + public void FromRgba32() { var rgb = default(Rgb24); rgb.FromRgba32(new Rgba32(1, 2, 3, 4)); @@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats a / 255f); [Fact] - public void PackFromVector4() + public void FromVector4() { var rgb = default(Rgb24); rgb.FromVector4(Vec(1, 2, 3, 4)); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index 444a627926..a7f0e5edfc 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats => Assert.Equal(Vector4.One, new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue).ToVector4()); [Fact] - public void Rgb48_PackFromScaledVector4() + public void Rgb48_FromScaledVector4() { // arrange var pixel = default(Rgb48); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs index 16aad79a0c..ad7df30769 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Rgba1010102_PackFromScaledVector4() + public void Rgba1010102_FromScaledVector4() { // arrange var rgba = new Rgba1010102(Vector4.One); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs index df83d14fbc..8c702f66da 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs @@ -159,7 +159,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Rgba32_PackFromScaledVector4() + public void Rgba32_FromScaledVector4() { // arrange var rgba = new Rgba32(Vector4.One); @@ -197,7 +197,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Rgba32_PackFromRgba32_ToRgba32() + public void Rgba32_FromRgba32_ToRgba32() { // arrange var rgba = default(Rgba32); @@ -213,7 +213,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Rgba32_PackFromBgra32_ToRgba32() + public void Rgba32_FromBgra32_ToRgba32() { // arrange var rgba = default(Rgba32); @@ -229,7 +229,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Rgba32_PackFromArgb32_ToArgb32() + public void Rgba32_FromArgb32_ToArgb32() { // arrange var rgba = default(Rgba32); @@ -245,7 +245,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Rgba32_PackFromRgb48() + public void Rgba32_FromRgb48() { // arrange var input = default(Rgba32); @@ -261,7 +261,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Rgba32_PackFromRgba64() + public void Rgba32_FromRgba64() { // arrange var input = default(Rgba32); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index d6a9db66f8..564c26b8b1 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Rgba64_PackFromScaledVector4() + public void Rgba64_FromScaledVector4() { // arrange var pixel = default(Rgba64); diff --git a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs index a6fec9e51a..e880e38517 100644 --- a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs @@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void RgbaVector_PackFromRgb48() + public void RgbaVector_FromRgb48() { // arrange var input = default(RgbaVector); @@ -132,7 +132,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void RgbaVector_PackFromRgba64() + public void RgbaVector_FromRgba64() { // arrange var input = default(RgbaVector); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs index b15384bf6b..725e1a0d14 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short2_PackFromScaledVector4() + public void Short2_FromScaledVector4() { // arrange var pixel = default(Short2); @@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short2_PackFromRgba32_ToRgba32() + public void Short2_FromRgba32_ToRgba32() { // arrange var short2 = default(Short2); @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short2_PackFromRgb48() + public void Short2_FromRgb48() { // arrange var input = default(Short2); @@ -127,7 +127,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short2_PackFromRgba64() + public void Short2_FromRgba64() { // arrange var input = default(Short2); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs index 6d45606bf3..b19917f34a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short4_PackFromScaledVector4() + public void Short4_FromScaledVector4() { // arrange var short4 = new Short4(Vector4.One * 0x7FFF); @@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short4_PackFromRgba32_ToRgba32() + public void Short4_FromRgba32_ToRgba32() { // arrange var short4 = default(Short4); @@ -115,7 +115,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short4_PackFromBgra32_ToRgba32() + public void Short4_FromBgra32_ToRgba32() { // arrange var short4 = default(Short4); @@ -131,7 +131,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short4_PackFromArgb32_ToRgba32() + public void Short4_FromArgb32_ToRgba32() { // arrange var short4 = default(Short4); @@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short4_PackFromRgb48_ToRgb48() + public void Short4_FromRgb48_ToRgb48() { // arrange var input = default(Short4); @@ -163,7 +163,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short4_PackFromRgba64_ToRgba64() + public void Short4_FromRgba64_ToRgba64() { // arrange var input = default(Short4); diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs index 7e942691e9..2409ff9add 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs @@ -31,14 +31,14 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs { byte[] data = pixels.ToByteArray(PixelMapping.RGBA); - PixelOperations.Instance.PackFromRgba32Bytes(data, resultPixels, resultPixels.Length); + PixelOperations.Instance.FromRgba32Bytes(data, resultPixels, resultPixels.Length); } else if (magickImage.Depth == 16) { ushort[] data = pixels.ToShortArray(PixelMapping.RGBA); Span bytes = MemoryMarshal.Cast(data.AsSpan()); - PixelOperations.Instance.PackFromRgba64Bytes(bytes, resultPixels, resultPixels.Length); + PixelOperations.Instance.FromRgba64Bytes(bytes, resultPixels, resultPixels.Length); } else { diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs index d06f5630f4..1543e2c8f4 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs @@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); - PixelOperations.Instance.PackFromBgra32(workBuffer.GetSpan(), row, row.Length); + PixelOperations.Instance.FromBgra32(workBuffer.GetSpan(), row, row.Length); } } } @@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); - PixelOperations.Instance.PackFromBgr24(workBuffer.GetSpan(), row, row.Length); + PixelOperations.Instance.FromBgr24(workBuffer.GetSpan(), row, row.Length); } } } diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index 9255634b2f..78927dece3 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Tests v.W = 1F; } - PixelOperations.Instance.PackFromScaledVector4(tempSpan, pixelSpan, pixelSpan.Length); + PixelOperations.Instance.FromScaledVector4(tempSpan, pixelSpan, pixelSpan.Length); } } }); From 5fda8d38be006a90de4810b1220eff453050d424 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 13:56:47 +0200 Subject: [PATCH 199/381] rename stuff in Benchmarks --- .../Color/Bulk/{PackFromXyzw.cs => FromRgba32Bytes.cs} | 4 ++-- .../Color/Bulk/{PackFromVector4.cs => FromVector4.cs} | 4 ++-- .../PixelConversion/PixelConversion_ConvertFromRgba32.cs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) rename tests/ImageSharp.Benchmarks/Color/Bulk/{PackFromXyzw.cs => FromRgba32Bytes.cs} (94%) rename tests/ImageSharp.Benchmarks/Color/Bulk/{PackFromVector4.cs => FromVector4.cs} (98%) diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs similarity index 94% rename from tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs rename to tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs index b1025e80ce..f3245ebaf5 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs @@ -13,7 +13,7 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk { - public abstract class PackFromXyzw + public abstract class FromRgba32Bytes where TPixel : struct, IPixel { private IMemoryOwner destination; @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - public class PackFromXyzw_Rgba32 : PackFromXyzw + public class FromRgba32BytesRgba32 : FromRgba32Bytes { } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs similarity index 98% rename from tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs rename to tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs index 3839bf58ee..72322f0d44 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs @@ -17,7 +17,7 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk { [Config(typeof(Config.ShortClr))] - public abstract class PackFromVector4 + public abstract class FromVector4 where TPixel : struct, IPixel { protected IMemoryOwner source; @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - public class PackFromVector4_Rgba32 : PackFromVector4 + public class FromVector4Rgba32 : FromVector4 { [Benchmark] public void FallbackIntrinsics128() diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs index 046c7dd90c..6a96c8576e 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs @@ -133,6 +133,6 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion * !!! Conclusion !!! * All memory-incompatible (permuted) variants are equivalent with the the "FromBytes" solution. * In memory compatible cases we should use the optimized Bulk-copying variant anyways, - * so there is no benefit introducing non-bulk API-s other than PackFromBytes() OR PackFromRgba32(). + * so there is no benefit introducing non-bulk API-s other than FromBytes() OR FromRgba32(). */ } \ No newline at end of file From fb1eba4f3de60b45bf4b816e4d7229c230593449 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 14:18:15 +0200 Subject: [PATCH 200/381] Introduce RgbaCompatible.Common.ttinclude --- .../Argb32.PixelOperations.Generated.cs | 12 ++-- .../Argb32.PixelOperations.Generated.tt | 58 +++---------------- .../Generated/RgbaCompatible.Common.ttinclude | 36 ++++++++++++ 3 files changed, 51 insertions(+), 55 deletions(-) create mode 100644 src/ImageSharp/PixelFormats/PixelImplementations/Generated/RgbaCompatible.Common.ttinclude diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs index 16121d62d8..507c8cd3ac 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs @@ -1,19 +1,19 @@ // 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.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Argb32 { - /// /// Provides optimized overrides for bulk operations. /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt index f903846719..4324211666 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt @@ -1,53 +1,13 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> +<#@include file="RgbaCompatible.Common.ttinclude" #> <#@ output extension=".cs" #> -<# - void GenerateConvertToMethod(string pixelType) - { - #> - - /// - internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) - { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - - dp.FromArgb32(sp); - } - } - <# - } -#> -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Argb32 { - /// /// Provides optimized overrides for bulk operations. /// @@ -70,14 +30,14 @@ namespace SixLabors.ImageSharp.PixelFormats } <# - GenerateConvertToMethod("Bgr24"); - GenerateConvertToMethod("Bgra32"); - GenerateConvertToMethod("Gray8"); - GenerateConvertToMethod("Gray16"); - GenerateConvertToMethod("Rgb24"); - GenerateConvertToMethod("Rgba32"); - GenerateConvertToMethod("Rgb48"); - GenerateConvertToMethod("Rgba64"); + GenerateDefaultConvertToMethod("Argb32", "Bgr24"); + GenerateDefaultConvertToMethod("Argb32", "Bgra32"); + GenerateDefaultConvertToMethod("Argb32", "Gray8"); + GenerateDefaultConvertToMethod("Argb32", "Gray16"); + GenerateDefaultConvertToMethod("Argb32", "Rgb24"); + GenerateDefaultConvertToMethod("Argb32", "Rgba32"); + GenerateDefaultConvertToMethod("Argb32", "Rgb48"); + GenerateDefaultConvertToMethod("Argb32", "Rgba64"); #> } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/RgbaCompatible.Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/RgbaCompatible.Common.ttinclude new file mode 100644 index 0000000000..d433bd5405 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/RgbaCompatible.Common.ttinclude @@ -0,0 +1,36 @@ +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +// + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +<#+ + void GenerateDefaultConvertToMethod(string fromPixelType, string toPixelType) + { + #> + + /// + internal override void To<#=toPixelType#>(ReadOnlySpan<<#=fromPixelType#>> sourcePixels, Span<<#=toPixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref <#=fromPixelType#> sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=toPixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref <#=fromPixelType#> sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=toPixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.From<#=fromPixelType#>(sp); + } + } + <#+ + } +#> \ No newline at end of file From f55050bcfbff74c9ed35a8be731a3a637758a515 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 14:22:55 +0200 Subject: [PATCH 201/381] GenerateDefaultSelfConversionMethods --- .../Argb32.PixelOperations.Generated.cs | 5 ++-- .../Argb32.PixelOperations.Generated.tt | 17 +------------- .../Generated/RgbaCompatible.Common.ttinclude | 23 +++++++++++++++++++ 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs index 507c8cd3ac..e5a2ffc2a2 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs @@ -19,7 +19,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal class PixelOperations : PixelOperations { - /// + + /// internal override void FromArgb32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -35,7 +36,7 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(destPixels); } - + /// internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) { diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt index 4324211666..a3e944f98c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt @@ -13,23 +13,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal class PixelOperations : PixelOperations { - /// - internal override void FromArgb32(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - source.Slice(0, count).CopyTo(destPixels); - } - - /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - sourcePixels.Slice(0, count).CopyTo(destPixels); - } - <# + GenerateDefaultSelfConversionMethods("Argb32"); GenerateDefaultConvertToMethod("Argb32", "Bgr24"); GenerateDefaultConvertToMethod("Argb32", "Bgra32"); GenerateDefaultConvertToMethod("Argb32", "Gray8"); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/RgbaCompatible.Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/RgbaCompatible.Common.ttinclude index d433bd5405..150607538b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/RgbaCompatible.Common.ttinclude +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/RgbaCompatible.Common.ttinclude @@ -11,6 +11,29 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; <#+ + void GenerateDefaultSelfConversionMethods(string pixelType) + { + #> + + /// + internal override void From<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void To<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <#+ + } + void GenerateDefaultConvertToMethod(string fromPixelType, string toPixelType) { #> From 0dedf86b0b403c2da244b40993ae749f9d36b297 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 15:04:15 +0200 Subject: [PATCH 202/381] DRY out PixelOperations generators --- .../Argb32.PixelOperations.Generated.cs | 1 + .../Argb32.PixelOperations.Generated.tt | 12 +-- .../Bgr24.PixelOperations.Generated.cs | 32 ++++---- .../Bgr24.PixelOperations.Generated.tt | 67 +---------------- .../Bgra32.PixelOperations.Generated.cs | 16 ++-- .../Bgra32.PixelOperations.Generated.tt | 67 +---------------- .../Gray16.PixelOperations.Generated.cs | 16 ++-- .../Gray16.PixelOperations.Generated.tt | 67 +---------------- .../Gray8.PixelOperations.Generated.cs | 16 ++-- .../Gray8.PixelOperations.Generated.tt | 67 +---------------- .../Rgb24.PixelOperations.Generated.cs | 16 ++-- .../Rgb24.PixelOperations.Generated.tt | 67 +---------------- .../Rgb48.PixelOperations.Generated.cs | 16 ++-- .../Rgb48.PixelOperations.Generated.tt | 67 +---------------- .../Rgba32.PixelOperations.Generated.cs | 22 +++--- .../Rgba32.PixelOperations.Generated.tt | 73 ++----------------- .../Rgba64.PixelOperations.Generated.cs | 16 ++-- .../Rgba64.PixelOperations.Generated.tt | 67 +---------------- ...ble.Common.ttinclude => _Common.ttinclude} | 15 ++++ 19 files changed, 120 insertions(+), 600 deletions(-) rename src/ImageSharp/PixelFormats/PixelImplementations/Generated/{RgbaCompatible.Common.ttinclude => _Common.ttinclude} (81%) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs index e5a2ffc2a2..655c4c3188 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs @@ -1,5 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. + // using System; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt index a3e944f98c..8c4c6b58af 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt @@ -1,4 +1,4 @@ -<#@include file="RgbaCompatible.Common.ttinclude" #> +<#@include file="_Common.ttinclude" #> <#@ output extension=".cs" #> namespace SixLabors.ImageSharp.PixelFormats @@ -14,15 +14,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { <# - GenerateDefaultSelfConversionMethods("Argb32"); - GenerateDefaultConvertToMethod("Argb32", "Bgr24"); - GenerateDefaultConvertToMethod("Argb32", "Bgra32"); - GenerateDefaultConvertToMethod("Argb32", "Gray8"); - GenerateDefaultConvertToMethod("Argb32", "Gray16"); - GenerateDefaultConvertToMethod("Argb32", "Rgb24"); - GenerateDefaultConvertToMethod("Argb32", "Rgba32"); - GenerateDefaultConvertToMethod("Argb32", "Rgb48"); - GenerateDefaultConvertToMethod("Argb32", "Rgba64"); + GenerateAllDefaultConversionMethods("Argb32"); #> } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs index cbfbe70991..5d2ca335e5 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs @@ -2,24 +2,26 @@ // Licensed under the Apache License, Version 2.0. // + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Bgr24 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// + + /// internal override void FromBgr24(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -35,7 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(destPixels); } - + /// internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) { @@ -43,7 +45,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); - + for (int i = 0; i < count; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); @@ -60,7 +62,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); - + for (int i = 0; i < count; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); @@ -77,7 +79,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); - + for (int i = 0; i < count; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); @@ -94,7 +96,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); - + for (int i = 0; i < count; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); @@ -111,7 +113,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); - + for (int i = 0; i < count; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); @@ -128,7 +130,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - + for (int i = 0; i < count; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); @@ -145,7 +147,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); - + for (int i = 0; i < count; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); @@ -162,7 +164,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); - + for (int i = 0; i < count; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt index 0f7bd838ff..56e3bf9ba4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt @@ -1,83 +1,20 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> +<#@include file="_Common.ttinclude" #> <#@ output extension=".cs" #> -<# - void GenerateConvertToMethod(string pixelType) - { - #> - - /// - internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); - - for (int i = 0; i < count; i++) - { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - dp.FromBgr24(sp); - } - } - <# - } -#> -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Bgr24 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// - internal override void FromBgr24(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - source.Slice(0, count).CopyTo(destPixels); - } - - /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - sourcePixels.Slice(0, count).CopyTo(destPixels); - } - <# - GenerateConvertToMethod("Argb32"); - GenerateConvertToMethod("Bgra32"); - GenerateConvertToMethod("Gray8"); - GenerateConvertToMethod("Gray16"); - GenerateConvertToMethod("Rgb24"); - GenerateConvertToMethod("Rgba32"); - GenerateConvertToMethod("Rgb48"); - GenerateConvertToMethod("Rgba64"); + GenerateAllDefaultConversionMethods("Bgr24"); #> } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs index edd702e0e0..1121f43437 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs @@ -2,24 +2,26 @@ // Licensed under the Apache License, Version 2.0. // + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Bgra32 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// + + /// internal override void FromBgra32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -35,7 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(destPixels); } - + /// internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) { diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt index 4c4e10fad0..6563ff9072 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt @@ -1,83 +1,20 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> +<#@include file="_Common.ttinclude" #> <#@ output extension=".cs" #> -<# - void GenerateConvertToMethod(string pixelType) - { - #> - - /// - internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) - { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra32(sp); - } - } - <# - } -#> -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Bgra32 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// - internal override void FromBgra32(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - source.Slice(0, count).CopyTo(destPixels); - } - - /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - sourcePixels.Slice(0, count).CopyTo(destPixels); - } - <# - GenerateConvertToMethod("Argb32"); - GenerateConvertToMethod("Bgr24"); - GenerateConvertToMethod("Gray8"); - GenerateConvertToMethod("Gray16"); - GenerateConvertToMethod("Rgb24"); - GenerateConvertToMethod("Rgba32"); - GenerateConvertToMethod("Rgb48"); - GenerateConvertToMethod("Rgba64"); + GenerateAllDefaultConversionMethods("Bgra32"); #> } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs index ca0e1fe326..e27f8bc587 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs @@ -2,24 +2,26 @@ // Licensed under the Apache License, Version 2.0. // + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Gray16 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// + + /// internal override void FromGray16(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -35,7 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(destPixels); } - + /// internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) { diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt index 1e500dac54..3db96d70a9 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt @@ -1,83 +1,20 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> +<#@include file="_Common.ttinclude" #> <#@ output extension=".cs" #> -<# - void GenerateConvertToMethod(string pixelType) - { - #> - - /// - internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) - { - ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - - dp.FromGray16(sp); - } - } - <# - } -#> -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Gray16 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// - internal override void FromGray16(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - source.Slice(0, count).CopyTo(destPixels); - } - - /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - sourcePixels.Slice(0, count).CopyTo(destPixels); - } - <# - GenerateConvertToMethod("Argb32"); - GenerateConvertToMethod("Bgr24"); - GenerateConvertToMethod("Bgra32"); - GenerateConvertToMethod("Gray8"); - GenerateConvertToMethod("Rgb24"); - GenerateConvertToMethod("Rgba32"); - GenerateConvertToMethod("Rgb48"); - GenerateConvertToMethod("Rgba64"); + GenerateAllDefaultConversionMethods("Gray16"); #> } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs index 6950c337d6..26ed91cfff 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs @@ -2,24 +2,26 @@ // Licensed under the Apache License, Version 2.0. // + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Gray8 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// + + /// internal override void FromGray8(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -35,7 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(destPixels); } - + /// internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) { diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt index 7c6e2f7675..a65d8f2634 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt @@ -1,83 +1,20 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> +<#@include file="_Common.ttinclude" #> <#@ output extension=".cs" #> -<# - void GenerateConvertToMethod(string pixelType) - { - #> - - /// - internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) - { - ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - - dp.FromGray8(sp); - } - } - <# - } -#> -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Gray8 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// - internal override void FromGray8(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - source.Slice(0, count).CopyTo(destPixels); - } - - /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - sourcePixels.Slice(0, count).CopyTo(destPixels); - } - <# - GenerateConvertToMethod("Argb32"); - GenerateConvertToMethod("Bgr24"); - GenerateConvertToMethod("Bgra32"); - GenerateConvertToMethod("Gray16"); - GenerateConvertToMethod("Rgb24"); - GenerateConvertToMethod("Rgba32"); - GenerateConvertToMethod("Rgb48"); - GenerateConvertToMethod("Rgba64"); + GenerateAllDefaultConversionMethods("Gray8"); #> } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs index 53234cd66e..8a6c6bddc1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs @@ -2,24 +2,26 @@ // Licensed under the Apache License, Version 2.0. // + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Rgb24 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// + + /// internal override void FromRgb24(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -35,7 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(destPixels); } - + /// internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) { diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt index b98e1e4c7c..796cdeb662 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt @@ -1,83 +1,20 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> +<#@include file="_Common.ttinclude" #> <#@ output extension=".cs" #> -<# - void GenerateConvertToMethod(string pixelType) - { - #> - - /// - internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) - { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb24(sp); - } - } - <# - } -#> -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Rgb24 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// - internal override void FromRgb24(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - source.Slice(0, count).CopyTo(destPixels); - } - - /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - sourcePixels.Slice(0, count).CopyTo(destPixels); - } - <# - GenerateConvertToMethod("Argb32"); - GenerateConvertToMethod("Bgr24"); - GenerateConvertToMethod("Bgra32"); - GenerateConvertToMethod("Gray8"); - GenerateConvertToMethod("Gray16"); - GenerateConvertToMethod("Rgba32"); - GenerateConvertToMethod("Rgb48"); - GenerateConvertToMethod("Rgba64"); + GenerateAllDefaultConversionMethods("Rgb24"); #> } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs index 61d13978ab..1701109edf 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs @@ -2,24 +2,26 @@ // Licensed under the Apache License, Version 2.0. // + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Rgb48 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// + + /// internal override void FromRgb48(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -35,7 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(destPixels); } - + /// internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) { diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt index 2ff3125b4c..b8ee99fce1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt @@ -1,83 +1,20 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> +<#@include file="_Common.ttinclude" #> <#@ output extension=".cs" #> -<# - void GenerateConvertToMethod(string pixelType) - { - #> - - /// - internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) - { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); - } - } - <# - } -#> -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Rgb48 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// - internal override void FromRgb48(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - source.Slice(0, count).CopyTo(destPixels); - } - - /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - sourcePixels.Slice(0, count).CopyTo(destPixels); - } - <# - GenerateConvertToMethod("Argb32"); - GenerateConvertToMethod("Bgr24"); - GenerateConvertToMethod("Bgra32"); - GenerateConvertToMethod("Gray8"); - GenerateConvertToMethod("Gray16"); - GenerateConvertToMethod("Rgb24"); - GenerateConvertToMethod("Rgba32"); - GenerateConvertToMethod("Rgba64"); + GenerateAllDefaultConversionMethods("Rgb48"); #> } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs index ae2ffd6888..fb817a29ae 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs @@ -2,24 +2,26 @@ // Licensed under the Apache License, Version 2.0. // + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Rgba32 { - - /// + /// /// Provides optimized overrides for bulk operations. - /// - internal partial class PixelOperations + /// + internal partial class PixelOperations : PixelOperations { - /// + + /// internal override void FromRgba32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -35,7 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(destPixels); } - + /// internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) { diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt index fb8d6db349..0c4a4c0c0a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt @@ -1,83 +1,20 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> +<#@include file="_Common.ttinclude" #> <#@ output extension=".cs" #> -<# - void GenerateConvertToMethod(string pixelType) - { - #> - - /// - internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) - { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba32(sp); - } - } - <# - } -#> -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Rgba32 { - - /// + /// /// Provides optimized overrides for bulk operations. - /// - internal partial class PixelOperations + /// + internal partial class PixelOperations : PixelOperations { - /// - internal override void FromRgba32(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - source.Slice(0, count).CopyTo(destPixels); - } - - /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - sourcePixels.Slice(0, count).CopyTo(destPixels); - } - <# - GenerateConvertToMethod("Argb32"); - GenerateConvertToMethod("Bgr24"); - GenerateConvertToMethod("Bgra32"); - GenerateConvertToMethod("Gray8"); - GenerateConvertToMethod("Gray16"); - GenerateConvertToMethod("Rgb24"); - GenerateConvertToMethod("Rgb48"); - GenerateConvertToMethod("Rgba64"); + GenerateAllDefaultConversionMethods("Rgba32"); #> } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs index 252068828e..d49fb7ae5e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs @@ -2,24 +2,26 @@ // Licensed under the Apache License, Version 2.0. // + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Rgba64 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// + + /// internal override void FromRgba64(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -35,7 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(destPixels); } - + /// internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) { diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt index 626f2316d3..9409e1573e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt @@ -1,83 +1,20 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> +<#@include file="_Common.ttinclude" #> <#@ output extension=".cs" #> -<# - void GenerateConvertToMethod(string pixelType) - { - #> - - /// - internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) - { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); - } - } - <# - } -#> -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Rgba64 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// - internal override void FromRgba64(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - source.Slice(0, count).CopyTo(destPixels); - } - - /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - sourcePixels.Slice(0, count).CopyTo(destPixels); - } - <# - GenerateConvertToMethod("Argb32"); - GenerateConvertToMethod("Bgr24"); - GenerateConvertToMethod("Bgra32"); - GenerateConvertToMethod("Gray8"); - GenerateConvertToMethod("Gray16"); - GenerateConvertToMethod("Rgb24"); - GenerateConvertToMethod("Rgba32"); - GenerateConvertToMethod("Rgb48"); + GenerateAllDefaultConversionMethods("Rgba64"); #> } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/RgbaCompatible.Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude similarity index 81% rename from src/ImageSharp/PixelFormats/PixelImplementations/Generated/RgbaCompatible.Common.ttinclude rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude index 150607538b..af8c42357e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/RgbaCompatible.Common.ttinclude +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude @@ -5,12 +5,15 @@ <#@ import namespace="System.Collections.Generic" #> // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. + // using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; <#+ + static readonly string[] CommonPixelTypeNames = { "Argb32", "Bgr24", "Bgra32", "Gray8", "Gray16", "Rgb24", "Rgba32", "Rgb48", "Rgba64" }; + void GenerateDefaultSelfConversionMethods(string pixelType) { #> @@ -56,4 +59,16 @@ using System.Runtime.InteropServices; } <#+ } + + void GenerateAllDefaultConversionMethods(string pixelType) + { + GenerateDefaultSelfConversionMethods(pixelType); + + var allOtherPixelTypes = CommonPixelTypeNames.Where(p => p != pixelType); + + foreach (string destPixelType in allOtherPixelTypes) + { + GenerateDefaultConvertToMethod(pixelType, destPixelType); + } + } #> \ No newline at end of file From ed55a1f75b280dd9996f41022b930d8b33f0b904 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 15:17:37 +0200 Subject: [PATCH 203/381] CLA assistant, please wake up! --- tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs b/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs index 950434ac32..629b3cdeb3 100644 --- a/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs +++ b/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs @@ -1,8 +1,9 @@ -using System; -using System.Runtime.CompilerServices; +// 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 Xunit; namespace SixLabors.ImageSharp.Tests.Helpers From 3986dedb3cb230a025986a679cc089b454299d11 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 16:43:31 +0200 Subject: [PATCH 204/381] Adapt Span.CopyTo(...) semantics on color conversion API-s --- .../Conversion/ColorSpaceConverter.CieLab.cs | 78 ++-- .../Conversion/ColorSpaceConverter.CieLch.cs | 79 ++-- .../ColorSpaceConverter.CieLchuv.cs | 79 ++-- .../Conversion/ColorSpaceConverter.CieLuv.cs | 79 ++-- .../Conversion/ColorSpaceConverter.CieXyy.cs | 79 ++-- .../Conversion/ColorSpaceConverter.CieXyz.cs | 82 ++-- .../Conversion/ColorSpaceConverter.Cmyk.cs | 79 ++-- .../Conversion/ColorSpaceConverter.Hsl.cs | 79 ++-- .../Conversion/ColorSpaceConverter.Hsv.cs | 79 ++-- .../ColorSpaceConverter.HunterLab.cs | 368 ++++++++--------- .../ColorSpaceConverter.LinearRgb.cs | 371 ++++++++--------- .../Conversion/ColorSpaceConverter.Lms.cs | 356 ++++++++--------- .../Conversion/ColorSpaceConverter.Rgb.cs | 377 +++++++++--------- .../Conversion/ColorSpaceConverter.YCbCr.cs | 351 ++++++++-------- .../Conversion/IChromaticAdaptation.cs | 7 +- .../Conversion/VonKriesChromaticAdaptation.cs | 9 +- src/ImageSharp/Common/Helpers/Guard.cs | 63 ++- .../CieLabAndCieLchConversionTests.cs | 4 +- .../CieLabAndCieLchuvConversionTests.cs | 4 +- .../CieLabAndCieLuvConversionTests.cs | 4 +- .../CieLabAndCieXyyConversionTests.cs | 4 +- .../CieLabAndCmykConversionTests.cs | 4 +- .../Conversion/CieLabAndHslConversionTests.cs | 4 +- .../Conversion/CieLabAndHsvConversionTests.cs | 4 +- .../CieLabAndHunterLabConversionTests.cs | 4 +- .../CieLabAndLinearRgbConversionTests.cs | 4 +- .../Conversion/CieLabAndLmsConversionTests.cs | 4 +- .../Conversion/CieLabAndRgbConversionTests.cs | 4 +- .../CieLabAndYCbCrConversionTests.cs | 4 +- .../CieLchAndCieLuvConversionTests.cs | 4 +- .../CieLchAndCieXyyConversionTests.cs | 4 +- .../Conversion/CieLchAndHslConversionTests.cs | 4 +- .../Conversion/CieLchAndHsvConversionTests.cs | 4 +- .../CieLchAndHunterLabConversionTests.cs | 4 +- .../CieLchAndLinearRgbConversionTests.cs | 4 +- .../Conversion/CieLchAndLmsConversionTests.cs | 4 +- .../Conversion/CieLchAndRgbConversionTests.cs | 4 +- .../CieLchAndYCbCrConversionTests.cs | 4 +- .../CieLchuvAndCieLchConversionTests.cs | 4 +- .../CieLchuvAndCieLuvConversionTests.cs | 4 +- .../CieLchuvAndCmykConversionTests.cs | 4 +- .../CieLuvAndCieXyyConversionTests.cs | 4 +- .../Conversion/CieLuvAndHslConversionTests.cs | 4 +- .../Conversion/CieLuvAndHsvConversionTests.cs | 4 +- .../CieLuvAndHunterLabConversionTests.cs | 4 +- .../CieLuvAndLinearRgbConversionTests.cs | 4 +- .../Conversion/CieLuvAndLmsConversionTests.cs | 4 +- .../Conversion/CieLuvAndRgbConversionTests.cs | 4 +- .../CieLuvAndYCbCrConversionTests.cs | 4 +- .../Conversion/CieXyyAndHslConversionTests.cs | 4 +- .../Conversion/CieXyyAndHsvConversionTests.cs | 4 +- .../CieXyyAndHunterLabConversionTests.cs | 4 +- .../CieXyyAndLinearRgbConversionTests.cs | 4 +- .../Conversion/CieXyyAndLmsConversionTests.cs | 4 +- .../Conversion/CieXyyAndRgbConversionTests.cs | 4 +- .../CieXyyAndYCbCrConversionTests.cs | 4 +- .../CieXyzAndCieLabConversionTest.cs | 4 +- .../CieXyzAndCieLchConversionTests.cs | 4 +- .../CieXyzAndCieLchuvConversionTests.cs | 4 +- .../CieXyzAndCieLuvConversionTest.cs | 4 +- .../CieXyzAndCieXyyConversionTest.cs | 4 +- .../Conversion/CieXyzAndHslConversionTests.cs | 4 +- .../Conversion/CieXyzAndHsvConversionTests.cs | 4 +- .../CieXyzAndHunterLabConversionTest.cs | 6 +- .../Conversion/CieXyzAndLmsConversionTest.cs | 4 +- .../CieXyzAndYCbCrConversionTests.cs | 4 +- .../CmykAndCieLchConversionTests.cs | 4 +- .../CmykAndCieLuvConversionTests.cs | 4 +- .../CmykAndCieXyyConversionTests.cs | 4 +- .../CmykAndCieXyzConversionTests.cs | 4 +- .../Conversion/CmykAndHslConversionTests.cs | 4 +- .../Conversion/CmykAndHsvConversionTests.cs | 4 +- .../CmykAndHunterLabConversionTests.cs | 4 +- .../Conversion/CmykAndYCbCrConversionTests.cs | 4 +- .../Conversion/RgbAndCieXyzConversionTest.cs | 8 +- .../Conversion/RgbAndCmykConversionTest.cs | 4 +- .../Conversion/RgbAndHslConversionTest.cs | 4 +- .../Conversion/RgbAndHsvConversionTest.cs | 4 +- .../Conversion/RgbAndYCbCrConversionTest.cs | 4 +- .../VonKriesChromaticAdaptationTests.cs | 2 +- tests/ImageSharp.Tests/Helpers/GuardTests.cs | 32 ++ 81 files changed, 1489 insertions(+), 1414 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs index 3ce14cdea4..3c197673d3 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs @@ -37,10 +37,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -70,10 +70,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -103,10 +103,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -136,10 +136,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -171,10 +171,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -203,10 +203,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -236,10 +236,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -268,10 +268,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -301,10 +301,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -334,10 +334,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -367,10 +367,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -400,10 +400,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -433,10 +433,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs index 3c9e6658cd..0a8607e3bc 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -37,10 +38,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -70,10 +71,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -103,10 +104,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -136,10 +137,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -169,10 +170,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -201,10 +202,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -234,10 +235,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -267,10 +268,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -300,10 +301,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -333,10 +334,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -366,10 +367,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -399,10 +400,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -432,10 +433,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs index 01de794885..3a779ee722 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -35,10 +36,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -68,10 +69,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -103,10 +104,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -136,10 +137,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -169,10 +170,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -202,10 +203,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -235,10 +236,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -268,10 +269,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -301,10 +302,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -334,10 +335,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -367,10 +368,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -400,10 +401,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -432,10 +433,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs index 0b469e065f..90eb8e34d7 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -31,10 +32,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -63,10 +64,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -98,10 +99,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -130,10 +131,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -165,10 +166,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -197,10 +198,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -229,10 +230,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -261,10 +262,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -293,10 +294,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -325,10 +326,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -357,10 +358,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -389,10 +390,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -421,10 +422,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs index b77f48325f..d03c10a01d 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -32,10 +33,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -65,10 +66,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -98,10 +99,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -131,10 +132,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -159,10 +160,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -192,10 +193,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -225,10 +226,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -258,10 +259,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -291,10 +292,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -324,10 +325,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -357,10 +358,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -390,10 +391,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -423,10 +424,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs index 8963ad495a..fada6d9c59 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -17,7 +18,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion private static readonly CieLuvToCieXyzConverter CieLuvToCieXyzConverter = new CieLuvToCieXyzConverter(); - private static readonly HunterLabToCieXyzConverter HunterLabToCieXyzConverter = new HunterLabToCieXyzConverter(); + private static readonly HunterLabToCieXyzConverter + HunterLabToCieXyzConverter = new HunterLabToCieXyzConverter(); private LinearRgbToCieXyzConverter linearRgbToCieXyzConverter; @@ -40,10 +42,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -75,10 +77,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -110,10 +112,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -145,10 +147,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -177,10 +179,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -211,10 +213,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -245,10 +247,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -279,10 +281,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -314,10 +316,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -350,10 +352,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -382,10 +384,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -415,10 +417,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -449,10 +451,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs index 6f8fe61469..b798516359 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -32,10 +33,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -65,10 +66,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -98,10 +99,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -131,10 +132,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -164,10 +165,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -197,10 +198,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -230,10 +231,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -263,10 +264,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -296,10 +297,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -329,10 +330,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -362,10 +363,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -390,10 +391,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -423,10 +424,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs index 106e8956f1..a7080b9749 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -32,10 +33,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -65,10 +66,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -98,10 +99,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -131,10 +132,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -164,10 +165,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -197,10 +198,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -230,10 +231,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -263,10 +264,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -296,10 +297,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -329,10 +330,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -362,10 +363,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -390,10 +391,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -423,10 +424,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs index 8b4e29215c..a2121203c1 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -32,10 +33,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -65,10 +66,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -98,10 +99,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -131,10 +132,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -164,10 +165,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -197,10 +198,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -230,10 +231,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -263,10 +264,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -296,10 +297,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -329,10 +330,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -362,10 +363,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -390,10 +391,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -423,10 +424,10 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs index b3286a9cc4..e5996c238e 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs @@ -12,26 +12,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// public partial class ColorSpaceConverter { - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieLab color) - { - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); @@ -44,26 +33,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieLch color) - { - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); @@ -76,26 +54,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieLchuv color) - { - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); @@ -108,26 +75,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieLuv color) - { - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); @@ -140,26 +96,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieXyy color) - { - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); @@ -172,29 +117,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieXyz color) - { - // Adaptation - CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetHunterLabWhitePoint); - - // Conversion - return this.cieXyzToHunterLabConverter.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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); @@ -207,26 +138,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in Cmyk color) - { - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); @@ -240,14 +160,24 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } /// - /// Converts a into a + /// Performs the bulk conversion from into /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in Hsl color) + /// The span to the source colors + /// The span to the destination colors + public void Convert(ReadOnlySpan source, Span destination) { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; + + 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); + } } /// @@ -255,180 +185,250 @@ 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsv 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 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 + /// Performs the bulk conversion from into /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in Hsv color) + /// The span to the source colors + /// The span to the destination colors + public void Convert(ReadOnlySpan source, Span destination) { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; + + 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); + } } /// - /// Performs the bulk conversion from into + /// 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); + ref Lms 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 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 + /// Performs the bulk conversion from into /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in LinearRgb color) + /// The span to the source colors + /// The span to the destination colors + public void Convert(ReadOnlySpan source, Span destination) { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; + + 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); + } } /// - /// Performs the bulk conversion from into + /// 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); + ref YCbCr 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 YCbCr sp = ref Unsafe.Add(ref sourceRef, i); ref HunterLab dp = ref Unsafe.Add(ref destRef, i); dp = this.ToHunterLab(sp); } } /// - /// Converts a into a + /// Converts a into a /// /// The color to convert. /// The - public HunterLab ToHunterLab(in Lms color) + public HunterLab ToHunterLab(in CieLab color) { var xyzColor = this.ToCieXyz(color); return this.ToHunterLab(xyzColor); } /// - /// Performs the bulk conversion from into + /// Converts a into a /// - /// The span to the source colors - /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + /// The color to convert. + /// The + public HunterLab ToHunterLab(in CieLch color) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); + } - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(in CieLchuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); + } - 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 + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(in CieLuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); } /// - /// Converts a into a + /// Converts a into a /// /// The color to convert. /// The - public HunterLab ToHunterLab(in Rgb color) + public HunterLab ToHunterLab(in CieXyy color) { var xyzColor = this.ToCieXyz(color); return this.ToHunterLab(xyzColor); } /// - /// Performs the bulk conversion from into + /// Converts a into a /// - /// The span to the source colors - /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + /// The color to convert. + /// The + public HunterLab ToHunterLab(in CieXyz color) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + // Adaptation + CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetHunterLabWhitePoint); - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + // Conversion + return this.cieXyzToHunterLabConverter.Convert(adapted); + } - 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 + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(in Cmyk color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); } /// - /// Converts a into a + /// Converts a into a /// /// The color to convert. /// The - public HunterLab ToHunterLab(in YCbCr color) + public HunterLab ToHunterLab(in Hsl color) { var xyzColor = this.ToCieXyz(color); return this.ToHunterLab(xyzColor); } /// - /// Performs the bulk conversion from into + /// Converts a into a /// - /// The span to the source colors - /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + /// The color to convert. + /// The + public HunterLab ToHunterLab(in Hsv color) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); + } - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(in LinearRgb color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); + } - 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); - } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(in Lms color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(in Rgb color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(in YCbCr color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); } } } \ 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 98943c034a..eef626be2f 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -15,26 +16,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { private static readonly RgbToLinearRgbConverter RgbToLinearRgbConverter = new RgbToLinearRgbConverter(); - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieLab color) - { - var xyzColor = this.ToCieXyz(color); - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -47,26 +37,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieLch color) - { - var xyzColor = this.ToCieXyz(color); - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -79,26 +58,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieLchuv color) - { - var xyzColor = this.ToCieXyz(color); - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -111,26 +79,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieLuv color) - { - var xyzColor = this.ToCieXyz(color); - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -143,26 +100,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieXyy color) - { - var xyzColor = this.ToCieXyz(color); - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -175,29 +121,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieXyz color) - { - // Adaptation - CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetRgbWorkingSpace.WhitePoint); - - // Conversion - return this.cieXyzToLinearRgbConverter.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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -210,26 +142,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in Cmyk color) - { - var rgb = this.ToRgb(color); - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -242,26 +163,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in Hsl color) - { - var rgb = this.ToRgb(color); - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -274,26 +184,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in Hsv color) - { - var rgb = this.ToRgb(color); - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -306,26 +205,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in HunterLab color) - { - var xyzColor = this.ToCieXyz(color); - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -338,26 +226,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in Lms color) - { - var xyzColor = this.ToCieXyz(color); - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -370,26 +247,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in Rgb color) - { - // 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -402,26 +268,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in YCbCr color) - { - var rgb = this.ToRgb(color); - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -433,5 +288,151 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion dp = this.ToLinearRgb(sp); } } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in CieLab color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLinearRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in CieLch color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLinearRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in CieLchuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLinearRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in CieLuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLinearRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in CieXyy color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLinearRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in CieXyz color) + { + // Adaptation + CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetRgbWorkingSpace.WhitePoint); + + // Conversion + return this.cieXyzToLinearRgbConverter.Convert(adapted); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in Cmyk color) + { + var rgb = this.ToRgb(color); + return this.ToLinearRgb(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in Hsl color) + { + var rgb = this.ToRgb(color); + return this.ToLinearRgb(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in Hsv color) + { + var rgb = this.ToRgb(color); + return this.ToLinearRgb(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in HunterLab color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLinearRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in Lms color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLinearRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in Rgb color) + { + // Conversion + return RgbToLinearRgbConverter.Convert(color); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in YCbCr color) + { + var rgb = this.ToRgb(color); + return this.ToLinearRgb(rgb); + } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs index ffd0f88d11..3b8638f7d2 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs @@ -12,26 +12,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// public partial class ColorSpaceConverter { - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieLab color) - { - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -44,26 +33,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieLch color) - { - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -76,26 +54,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieLchuv color) - { - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -108,26 +75,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieLuv color) - { - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -140,26 +96,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieXyy color) - { - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -172,22 +117,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieXyz color) => this.cieXyzAndLmsConverter.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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -200,26 +138,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in Cmyk color) - { - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -232,26 +159,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in Hsl color) - { - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -264,26 +180,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in Hsv color) - { - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -296,26 +201,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in HunterLab color) - { - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -328,26 +222,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in LinearRgb color) - { - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -360,26 +243,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in Rgb color) - { - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -392,26 +264,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in YCbCr color) - { - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -423,5 +284,144 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion dp = this.ToLms(sp); } } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in CieLab color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in CieLch color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in CieLchuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in CieLuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in CieXyy color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in CieXyz color) => this.cieXyzAndLmsConverter.Convert(color); + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in Cmyk color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in Hsl color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in Hsv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in HunterLab color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in LinearRgb color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in Rgb color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in YCbCr color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs index cd40c966b1..fc5665e5c1 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -15,26 +16,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { private static readonly LinearRgbToRgbConverter LinearRgbToRgbConverter = new LinearRgbToRgbConverter(); - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieLab color) - { - var xyzColor = this.ToCieXyz(color); - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -47,26 +37,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieLch color) - { - var xyzColor = this.ToCieXyz(color); - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -79,26 +58,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieLchuv color) - { - var xyzColor = this.ToCieXyz(color); - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -111,26 +79,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieLuv color) - { - var xyzColor = this.ToCieXyz(color); - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -143,26 +100,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieXyy color) - { - var xyzColor = this.ToCieXyz(color); - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -175,29 +121,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieXyz color) - { - // Conversion - var linear = this.ToLinearRgb(color); - - // Compand - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -210,26 +142,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in Cmyk color) - { - // 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -242,26 +163,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in Hsv color) - { - // 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -274,26 +184,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in Hsl color) - { - // 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -306,26 +205,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in HunterLab color) - { - var xyzColor = this.ToCieXyz(color); - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -338,26 +226,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in LinearRgb color) - { - // 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -370,26 +247,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in Lms color) - { - var xyzColor = this.ToCieXyz(color); - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -402,29 +268,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in YCbCr color) - { - // Conversion - Rgb rgb = YCbCrAndRgbConverter.Convert(color); - - // 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -436,5 +288,154 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion dp = this.ToRgb(sp); } } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in CieLab color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in CieLch color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in CieLchuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in CieLuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in CieXyy color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in CieXyz color) + { + // Conversion + var linear = this.ToLinearRgb(color); + + // Compand + return this.ToRgb(linear); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in Cmyk color) + { + // Conversion + return CmykAndRgbConverter.Convert(color); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in Hsv color) + { + // Conversion + return HsvAndRgbConverter.Convert(color); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in Hsl color) + { + // Conversion + return HslAndRgbConverter.Convert(color); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in HunterLab color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in LinearRgb color) + { + // Conversion + return LinearRgbToRgbConverter.Convert(color); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in Lms color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in YCbCr color) + { + // Conversion + Rgb rgb = YCbCrAndRgbConverter.Convert(color); + + // Adaptation + return this.Adapt(rgb); + } } } \ 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 38e6d5fae0..5780f4f545 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -15,27 +16,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { private static readonly YCbCrAndRgbConverter YCbCrAndRgbConverter = new YCbCrAndRgbConverter(); - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieLab color) - { - var xyzColor = this.ToCieXyz(color); - - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -48,27 +37,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieLch color) - { - var xyzColor = this.ToCieXyz(color); - - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -81,27 +58,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieLuv color) - { - var xyzColor = this.ToCieXyz(color); - - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -114,27 +79,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieXyy color) - { - var xyzColor = this.ToCieXyz(color); - - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -147,27 +100,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieXyz color) - { - var rgb = this.ToRgb(color); - - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -180,27 +121,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in Cmyk color) - { - var rgb = this.ToRgb(color); - - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -213,27 +142,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in Hsl color) - { - var rgb = this.ToRgb(color); - - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -246,27 +163,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in Hsv color) - { - var rgb = this.ToRgb(color); - - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -279,27 +184,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in HunterLab color) - { - var xyzColor = this.ToCieXyz(color); - - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -312,27 +205,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in LinearRgb color) - { - var rgb = this.ToRgb(color); - - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -345,27 +226,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in Lms color) - { - var xyzColor = this.ToCieXyz(color); - - 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -378,22 +247,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in Rgb color) => 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(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -405,5 +267,144 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion dp = this.ToYCbCr(sp); } } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in CieLab color) + { + var xyzColor = this.ToCieXyz(color); + + return this.ToYCbCr(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in CieLch color) + { + var xyzColor = this.ToCieXyz(color); + + return this.ToYCbCr(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in CieLuv color) + { + var xyzColor = this.ToCieXyz(color); + + return this.ToYCbCr(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in CieXyy color) + { + var xyzColor = this.ToCieXyz(color); + + return this.ToYCbCr(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in CieXyz color) + { + var rgb = this.ToRgb(color); + + return YCbCrAndRgbConverter.Convert(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in Cmyk color) + { + var rgb = this.ToRgb(color); + + return YCbCrAndRgbConverter.Convert(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in Hsl color) + { + var rgb = this.ToRgb(color); + + return YCbCrAndRgbConverter.Convert(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in Hsv color) + { + var rgb = this.ToRgb(color); + + return YCbCrAndRgbConverter.Convert(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in HunterLab color) + { + var xyzColor = this.ToCieXyz(color); + + return this.ToYCbCr(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in LinearRgb color) + { + var rgb = this.ToRgb(color); + + return YCbCrAndRgbConverter.Convert(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in Lms color) + { + var xyzColor = this.ToCieXyz(color); + + return this.ToYCbCr(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in Rgb color) => 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 1b14c6413e..69877d8b55 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs @@ -30,7 +30,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// 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); + void Transform( + ReadOnlySpan source, + Span destination, + CieXyz sourceWhitePoint, + in CieXyz destinationWhitePoint); } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs index 9b200b8736..85a36331b2 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs @@ -65,9 +65,14 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } /// - public void Transform(Span source, Span destination, CieXyz sourceWhitePoint, in CieXyz destinationWhitePoint, int count) + public void Transform( + ReadOnlySpan source, + Span destination, + CieXyz sourceWhitePoint, + in CieXyz destinationWhitePoint) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; if (sourceWhitePoint.Equals(destinationWhitePoint)) { diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs index 34ba544726..ef928c2800 100644 --- a/src/ImageSharp/Common/Helpers/Guard.cs +++ b/src/ImageSharp/Common/Helpers/Guard.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp { @@ -19,6 +20,7 @@ namespace SixLabors.ImageSharp /// The target object, which cannot be null. /// The name of the parameter that is to be checked. /// is null + [MethodImpl(InliningOptions.ShortMethod)] public static void NotNull(T value, string parameterName) where T : class { @@ -35,6 +37,7 @@ namespace SixLabors.ImageSharp /// Name of the parameter. /// is null. /// is empty or contains only blanks. + [MethodImpl(InliningOptions.ShortMethod)] public static void NotNullOrWhiteSpace(string value, string parameterName) { if (value is null) @@ -56,6 +59,7 @@ namespace SixLabors.ImageSharp /// Name of the parameter. /// is null. /// is empty. + [MethodImpl(InliningOptions.ShortMethod)] public static void NotNullOrEmpty(ICollection value, string parameterName) { if (value is null) @@ -79,6 +83,7 @@ namespace SixLabors.ImageSharp /// /// is greater than the maximum value. /// + [MethodImpl(InliningOptions.ShortMethod)] public static void MustBeLessThan(TValue value, TValue max, string parameterName) where TValue : IComparable { @@ -99,6 +104,7 @@ namespace SixLabors.ImageSharp /// /// is greater than the maximum value. /// + [MethodImpl(InliningOptions.ShortMethod)] public static void MustBeLessThanOrEqualTo(TValue value, TValue max, string parameterName) where TValue : IComparable { @@ -119,6 +125,7 @@ namespace SixLabors.ImageSharp /// /// is less than the minimum value. /// + [MethodImpl(InliningOptions.ShortMethod)] public static void MustBeGreaterThan(TValue value, TValue min, string parameterName) where TValue : IComparable { @@ -141,6 +148,7 @@ namespace SixLabors.ImageSharp /// /// is less than the minimum value. /// + [MethodImpl(InliningOptions.ShortMethod)] public static void MustBeGreaterThanOrEqualTo(TValue value, TValue min, string parameterName) where TValue : IComparable { @@ -162,6 +170,7 @@ namespace SixLabors.ImageSharp /// /// is less than the minimum value of greater than the maximum value. /// + [MethodImpl(InliningOptions.ShortMethod)] public static void MustBeBetweenOrEqualTo(TValue value, TValue min, TValue max, string parameterName) where TValue : IComparable { @@ -181,6 +190,7 @@ namespace SixLabors.ImageSharp /// /// is false /// + [MethodImpl(InliningOptions.ShortMethod)] public static void IsTrue(bool target, string parameterName, string message) { if (!target) @@ -199,6 +209,7 @@ namespace SixLabors.ImageSharp /// /// is true /// + [MethodImpl(InliningOptions.ShortMethod)] public static void IsFalse(bool target, string parameterName, string message) { if (target) @@ -217,6 +228,7 @@ namespace SixLabors.ImageSharp /// /// has less than items /// + [MethodImpl(InliningOptions.ShortMethod)] public static void MustBeSizedAtLeast(ReadOnlySpan source, int minLength, string parameterName) { if (source.Length < minLength) @@ -225,6 +237,26 @@ namespace SixLabors.ImageSharp } } + /// + /// Verifies that the 'destination' span is not shorter than 'source'. + /// + /// The source element type + /// The destination element type + /// The source span + /// The destination span + /// The name of the argument for 'destination' + [MethodImpl(InliningOptions.ShortMethod)] + public static void DestinationShouldNotBeTooShort( + ReadOnlySpan source, + Span destination, + string destinationParamName) + { + if (destination.Length < source.Length) + { + throw new ArgumentException($"Destination span is too short!", destinationParamName); + } + } + /// /// Verifies, that the `source` span has the length of 'minLength', or longer. /// @@ -235,6 +267,7 @@ namespace SixLabors.ImageSharp /// /// has less than items /// + [MethodImpl(InliningOptions.ShortMethod)] public static void MustBeSizedAtLeast(Span source, int minLength, string parameterName) { if (source.Length < minLength) @@ -255,7 +288,7 @@ namespace SixLabors.ImageSharp /// The destination parameter name /// The minimum length public static void SpansMustBeSizedAtLeast( - Span source, + ReadOnlySpan source, string sourceParamName, Span dest, string destParamName, @@ -265,26 +298,16 @@ namespace SixLabors.ImageSharp 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) + [MethodImpl(InliningOptions.ColdPath)] + private static void ThrowArgumentException(string message, string parameterName) { - MustBeSizedAtLeast(source, minLength, sourceParamName); - MustBeSizedAtLeast(dest, minLength, destParamName); + throw new ArgumentException(message, parameterName); + } + + [MethodImpl(InliningOptions.ColdPath)] + private static void ThrowArgumentNullException(string message) + { + throw new ArgumentException(message); } } } diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs index eb9a50d185..38c0c21bc9 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs index 7fb5770ddb..96628977fe 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs index 14a1c6fd37..39011bb292 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs index 9a42a9d47d..f7dc365b81 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs index 944fab574e..43300ab88c 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs index 836be1bf27..4ab309fe14 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs index fb1982bfc8..e7ff34f494 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs index 7e3c4251bf..844cda4760 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs index a43f0095d7..74ed180f38 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLinearRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs index 62d08263a6..a3db00e804 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLms(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs index 1b30412752..fc202ccc96 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs index 53d33af2b1..3e481d4f64 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs index e465757ef7..078ba44daf 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs index 18b8a47397..a65f618835 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs index d00a164c08..49990fb908 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs index d3ff04a759..924b45b4a0 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs index 852e56110b..0991657310 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs index 80b72cb2c2..a7a819d1f7 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLinearRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs index 314734ff2e..b83b861be8 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLms(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs index 389528dcd3..932fdc4105 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs index a2bd7eadc7..4d04418d99 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs index e7f511bab1..3cdaa42792 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs index 3bc4fd519b..6829c62b50 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs index f3940e4d14..0c62ffcc31 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs index 61bfe79634..3b41204f7c 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs index 7bc430aa37..bfc0d2ecf1 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs index 23cc5082c4..f11b17fff3 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs index 04699bde46..de2329c2ec 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs index 98914a6b92..3a1bd10c41 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLinearRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs index 306d60b531..f3881f10f7 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLms(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs index 21cf08dede..644f4577bf 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs index 8c07c38d60..41b9dba091 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs index fb415f43ba..5b36beaab9 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs index 3c8aee807a..da77378759 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs index 1fcbb75cb2..96d14c98a6 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs index 8c45378ed4..0339730945 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLinearRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs index 67ec26f6d4..fb0e06e6bb 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLms(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs index e309e2d555..5bbcd90875 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs index 3e33f05192..1ee84ef2e5 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs index 746e37c0e6..49b99b7052 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieLab(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs index 89d78ece1f..77f0c69699 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs index fbd602d9a0..24e134d732 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs index c0856a2bc1..761b9851e3 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieLuv(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs index 3f5ea4cfd8..2b0350cea1 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs index 8443722641..cd1c9f2c3e 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs index 327d660c6c..8112f6a198 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs index d162940151..2fed3e9c55 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToHunterLab(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs index 484d302e9a..75634eb51e 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToLms(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs index eacdc7ffba..9ea890f101 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs index 4a0c88c841..dbb0c6e200 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs index 2131ba630b..5fcc59090b 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs index ac93aaf25b..7ff80c170b 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs index cbb8f7dc4e..8017302059 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs index 1c9ad170d3..3464fdbbde 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs index 6fd1ba88ec..26af5ddd30 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs index e92ac2e528..dc40ee518e 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs index 575122661a..00569ced2e 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs index a3b0cbd953..8a2cd1159e 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToRgb(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); @@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToRgb(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); @@ -122,7 +122,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -159,7 +159,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs index 2b03ee9883..b01e3a854c 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs index 22f5c6d514..502df84133 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs index e84ce97237..9adc94af7c 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs @@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs index f5c7dbae66..94879eee7a 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs index cfd48b694d..b1427f4d5f 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion Span actualSpan = new CieXyz[5]; - adaptation.Transform(inputSpan, actualSpan, sourceWhitePoint, destinationWhitePoint, inputSpan.Length); + adaptation.Transform(inputSpan, actualSpan, sourceWhitePoint, destinationWhitePoint); for (int i = 0; i < inputSpan.Length; i++) { diff --git a/tests/ImageSharp.Tests/Helpers/GuardTests.cs b/tests/ImageSharp.Tests/Helpers/GuardTests.cs index 0d1bb5ce9f..b847e581f5 100644 --- a/tests/ImageSharp.Tests/Helpers/GuardTests.cs +++ b/tests/ImageSharp.Tests/Helpers/GuardTests.cs @@ -3,7 +3,10 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Linq; + using Xunit; +// ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Helpers { @@ -16,6 +19,35 @@ namespace SixLabors.ImageSharp.Tests.Helpers { } + [Theory] + [InlineData(0, 0)] + [InlineData(0, 1)] + [InlineData(0, 42)] + [InlineData(1, 1)] + [InlineData(10, 42)] + [InlineData(42, 42)] + public void DestinationShouldNotBeTooShort_WhenOk(int sourceLength, int destLength) + { + ReadOnlySpan source = new int[sourceLength]; + Span dest = new float[destLength]; + + Guard.DestinationShouldNotBeTooShort(source, dest, nameof(dest)); + } + + [Theory] + [InlineData(1, 0)] + [InlineData(42, 41)] + public void DestinationShouldNotBeTooShort_WhenThrows(int sourceLength, int destLength) + { + Assert.ThrowsAny( + () => + { + ReadOnlySpan source = new int[sourceLength]; + Span dest = new float[destLength]; + Guard.DestinationShouldNotBeTooShort(source, dest, nameof(dest)); + }); + } + /// /// Tests that the method throws when the argument is null. /// From cf9476be963425b6c40b02e6b3a1307a519f294f Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 16:50:15 +0200 Subject: [PATCH 205/381] Improve Guard --- src/ImageSharp/Common/Helpers/Guard.cs | 73 ++++++++++++-------------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs index ef928c2800..cd53e3d69a 100644 --- a/src/ImageSharp/Common/Helpers/Guard.cs +++ b/src/ImageSharp/Common/Helpers/Guard.cs @@ -21,12 +21,13 @@ namespace SixLabors.ImageSharp /// The name of the parameter that is to be checked. /// is null [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void NotNull(T value, string parameterName) where T : class { if (value is null) { - throw new ArgumentNullException(parameterName); + ThrowArgumentNullException(parameterName); } } @@ -38,16 +39,17 @@ namespace SixLabors.ImageSharp /// is null. /// is empty or contains only blanks. [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void NotNullOrWhiteSpace(string value, string parameterName) { if (value is null) { - throw new ArgumentNullException(parameterName); + ThrowArgumentNullException(parameterName); } if (string.IsNullOrWhiteSpace(value)) { - throw new ArgumentException("Must not be empty or whitespace.", parameterName); + ThrowArgumentException("Must not be empty or whitespace.", parameterName); } } @@ -60,16 +62,17 @@ namespace SixLabors.ImageSharp /// is null. /// is empty. [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void NotNullOrEmpty(ICollection value, string parameterName) { if (value is null) { - throw new ArgumentNullException(parameterName); + ThrowArgumentNullException(parameterName); } if (value.Count == 0) { - throw new ArgumentException("Must not be empty.", parameterName); + ThrowArgumentException("Must not be empty.", parameterName); } } @@ -84,12 +87,13 @@ namespace SixLabors.ImageSharp /// is greater than the maximum value. /// [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void MustBeLessThan(TValue value, TValue max, string parameterName) where TValue : IComparable { if (value.CompareTo(max) >= 0) { - throw new ArgumentOutOfRangeException(parameterName, $"Value {value} must be less than {max}."); + ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be less than {max}."); } } @@ -105,12 +109,13 @@ namespace SixLabors.ImageSharp /// is greater than the maximum value. /// [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void MustBeLessThanOrEqualTo(TValue value, TValue max, string parameterName) where TValue : IComparable { if (value.CompareTo(max) > 0) { - throw new ArgumentOutOfRangeException(parameterName, $"Value {value} must be less than or equal to {max}."); + ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be less than or equal to {max}."); } } @@ -126,12 +131,13 @@ namespace SixLabors.ImageSharp /// is less than the minimum value. /// [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void MustBeGreaterThan(TValue value, TValue min, string parameterName) where TValue : IComparable { if (value.CompareTo(min) <= 0) { - throw new ArgumentOutOfRangeException( + ThrowArgumentOutOfRangeException( parameterName, $"Value {value} must be greater than {min}."); } @@ -149,12 +155,13 @@ namespace SixLabors.ImageSharp /// is less than the minimum value. /// [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void MustBeGreaterThanOrEqualTo(TValue value, TValue min, string parameterName) where TValue : IComparable { if (value.CompareTo(min) < 0) { - throw new ArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min}."); + ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min}."); } } @@ -171,12 +178,13 @@ namespace SixLabors.ImageSharp /// is less than the minimum value of greater than the maximum value. /// [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void MustBeBetweenOrEqualTo(TValue value, TValue min, TValue max, string parameterName) where TValue : IComparable { if (value.CompareTo(min) < 0 || value.CompareTo(max) > 0) { - throw new ArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min} and less than or equal to {max}."); + ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min} and less than or equal to {max}."); } } @@ -191,11 +199,12 @@ namespace SixLabors.ImageSharp /// is false /// [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void IsTrue(bool target, string parameterName, string message) { if (!target) { - throw new ArgumentException(message, parameterName); + ThrowArgumentException(message, parameterName); } } @@ -210,11 +219,12 @@ namespace SixLabors.ImageSharp /// is true /// [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void IsFalse(bool target, string parameterName, string message) { if (target) { - throw new ArgumentException(message, parameterName); + ThrowArgumentException(message, parameterName); } } @@ -229,11 +239,12 @@ namespace SixLabors.ImageSharp /// has less than items /// [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void MustBeSizedAtLeast(ReadOnlySpan source, int minLength, string parameterName) { if (source.Length < minLength) { - throw new ArgumentException($"Span-s must be at least of length {minLength}!", parameterName); + ThrowArgumentException($"Span-s must be at least of length {minLength}!", parameterName); } } @@ -246,6 +257,7 @@ namespace SixLabors.ImageSharp /// The destination span /// The name of the argument for 'destination' [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void DestinationShouldNotBeTooShort( ReadOnlySpan source, Span destination, @@ -253,7 +265,7 @@ namespace SixLabors.ImageSharp { if (destination.Length < source.Length) { - throw new ArgumentException($"Destination span is too short!", destinationParamName); + ThrowArgumentException($"Destination span is too short!", destinationParamName); } } @@ -268,46 +280,31 @@ namespace SixLabors.ImageSharp /// has less than items /// [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void MustBeSizedAtLeast(Span source, int minLength, string parameterName) { if (source.Length < minLength) { - throw new ArgumentException($"Span-s must be at least of length {minLength}!", parameterName); + ThrowArgumentException($"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( - ReadOnlySpan source, - string sourceParamName, - Span dest, - string destParamName, - int minLength) + [MethodImpl(InliningOptions.ColdPath)] + private static void ThrowArgumentException(string message, string parameterName) { - MustBeSizedAtLeast(source, minLength, sourceParamName); - MustBeSizedAtLeast(dest, minLength, destParamName); + throw new ArgumentException(message, parameterName); } [MethodImpl(InliningOptions.ColdPath)] - private static void ThrowArgumentException(string message, string parameterName) + private static void ThrowArgumentOutOfRangeException(string parameterName, string message) { - throw new ArgumentException(message, parameterName); + throw new ArgumentOutOfRangeException(parameterName, message); } [MethodImpl(InliningOptions.ColdPath)] - private static void ThrowArgumentNullException(string message) + private static void ThrowArgumentNullException(string parameterName) { - throw new ArgumentException(message); + throw new ArgumentNullException(parameterName); } } } From ebff0a51e19d6d122d5c7a709ed511d7112f9233 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 17:03:06 +0200 Subject: [PATCH 206/381] Span.CopyTo(...) semantics for bulk Vecto4 conversion in PixelOperations --- .../Decoder/JpegImagePostProcessor.cs | 3 +- .../PixelFormats/PixelBlender{TPixel}.cs | 12 ++++---- .../Rgba32.PixelOperations.cs | 25 ++++++++--------- .../RgbaVector.PixelOperations.cs | 20 +++++++------ .../PixelFormats/PixelOperations{TPixel}.cs | 28 ++++++++----------- .../Convolution/Convolution2DProcessor.cs | 4 +-- .../Convolution/Convolution2PassProcessor.cs | 4 +-- .../Convolution/ConvolutionProcessor.cs | 4 +-- .../Dithering/PaletteDitherProcessorBase.cs | 2 +- .../FrameQuantizerBase{TPixel}.cs | 2 +- .../PaletteFrameQuantizer{TPixel}.cs | 2 +- .../Processors/Transforms/ResizeProcessor.cs | 4 +-- .../PixelFormats/PixelOperationsTests.cs | 10 +++---- .../TestUtilities/TestImageExtensions.cs | 4 +-- 14 files changed, 62 insertions(+), 62 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs index eb618dff0e..6bd287732d 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs @@ -159,7 +159,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder Span destRow = destination.GetPixelRowSpan(yy); - PixelOperations.Instance.FromVector4(this.rgbaBuffer.GetSpan(), destRow, destination.Width); + // TODO: Investigate if slicing is actually necessary + PixelOperations.Instance.FromVector4(this.rgbaBuffer.GetSpan().Slice(0, destRow.Length), destRow); } } } diff --git a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs index 48a83335a0..6c24ce05b2 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.ToScaledVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToScaledVector4(source, sourceSpan, destination.Length); + PixelOperations.Instance.ToScaledVector4(background, backgroundSpan); + PixelOperations.Instance.ToScaledVector4(source, sourceSpan); this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); - PixelOperations.Instance.FromScaledVector4(destinationSpan, destination, destination.Length); + PixelOperations.Instance.FromScaledVector4(destinationSpan, destination); } } @@ -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.ToScaledVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToScaledVector4(source, sourceSpan, destination.Length); + PixelOperations.Instance.ToScaledVector4(background, backgroundSpan); + PixelOperations.Instance.ToScaledVector4(source, sourceSpan); this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); - PixelOperations.Instance.FromScaledVector4(destinationSpan, destination, destination.Length); + PixelOperations.Instance.FromScaledVector4(destinationSpan, destination); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs index 4da9f101bc..c25baa4512 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs @@ -19,13 +19,11 @@ namespace SixLabors.ImageSharp.PixelFormats internal partial class PixelOperations : PixelOperations { /// - internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) + internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors) { - Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); - Guard.MustBeSizedAtLeast(destinationVectors, count, nameof(destinationVectors)); + Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); - sourceColors = sourceColors.Slice(0, count); - destinationVectors = destinationVectors.Slice(0, count); + destinationVectors = destinationVectors.Slice(0, sourceColors.Length); SimdUtils.BulkConvertByteToNormalizedFloat( MemoryMarshal.Cast(sourceColors), @@ -33,12 +31,11 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void FromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) + internal override void FromVector4(ReadOnlySpan sourceVectors, Span destinationColors) { - GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); - sourceVectors = sourceVectors.Slice(0, count); - destinationColors = destinationColors.Slice(0, count); + destinationColors = destinationColors.Slice(0, sourceVectors.Length); SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( MemoryMarshal.Cast(sourceVectors), @@ -46,15 +43,17 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) + internal override void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors) { - this.ToVector4(sourceColors, destinationVectors, count); + this.ToVector4(sourceColors, destinationVectors); } /// - internal override void FromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) + internal override void FromScaledVector4( + ReadOnlySpan sourceVectors, + Span destinationColors) { - this.FromVector4(sourceVectors, destinationColors, count); + this.FromVector4(sourceVectors, destinationColors); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs index ae64ed4de3..d1f3263659 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs @@ -18,23 +18,27 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void FromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) + internal override void FromScaledVector4( + ReadOnlySpan sourceVectors, + Span destinationColors) { - GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); - MemoryMarshal.Cast(sourceVectors).Slice(0, count).CopyTo(destinationColors); + MemoryMarshal.Cast(sourceVectors).CopyTo(destinationColors); } /// - internal override void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) - => this.ToVector4(sourceColors, destinationVectors, count); + internal override void ToScaledVector4( + ReadOnlySpan sourceColors, + Span destinationVectors) + => this.ToVector4(sourceColors, destinationVectors); /// - internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) + internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors) { - GuardSpans(sourceColors, nameof(sourceColors), destinationVectors, nameof(destinationVectors), count); + Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); - MemoryMarshal.Cast(sourceColors).Slice(0, count).CopyTo(destinationVectors); + MemoryMarshal.Cast(sourceColors).CopyTo(destinationVectors); } } } diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index af7690c62d..e6ccaf914d 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -26,15 +26,14 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The to the source vectors. /// The to the destination colors. - /// The number of pixels to convert. - internal virtual void FromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) + internal virtual void FromVector4(ReadOnlySpan sourceVectors, Span destinationColors) { - GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourceVectors.Length; i++) { ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); ref TPixel dp = ref Unsafe.Add(ref destRef, i); @@ -47,15 +46,14 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The to the source colors. /// The to the destination vectors. - /// The number of pixels to convert. - internal virtual void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) + internal virtual void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors) { - GuardSpans(sourceColors, nameof(sourceColors), destinationVectors, nameof(destinationVectors), count); + Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourceColors.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); ref Vector4 dp = ref Unsafe.Add(ref destRef, i); @@ -68,15 +66,14 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The to the source vectors. /// The to the destination colors. - /// The number of pixels to convert. - internal virtual void FromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) + internal virtual void FromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors) { - GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourceVectors.Length; i++) { ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); ref TPixel dp = ref Unsafe.Add(ref destRef, i); @@ -89,15 +86,14 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The to the source colors. /// The to the destination vectors. - /// The number of pixels to convert. - internal virtual void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) + internal virtual void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors) { - GuardSpans(sourceColors, nameof(sourceColors), destinationVectors, nameof(destinationVectors), count); + Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourceColors.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); ref Vector4 dp = ref Unsafe.Add(ref destRef, i); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs index df4df64cad..90049a994d 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs @@ -75,14 +75,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan, length); + PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve2D(in matrixY, in matrixX, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan, length); + PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan); } }); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs index 03447531ef..f38f16f1a9 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs @@ -93,14 +93,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan, length); + PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve(in matrix, sourcePixels, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan, length); + PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan); } }); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs index a42b777feb..d1b3f0ccf8 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs @@ -59,14 +59,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan, length); + PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve(in matrix, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan, length); + PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan); } }); diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs index a1bbe72733..fd93801092 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs @@ -31,7 +31,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering { this.Palette = palette ?? throw new ArgumentNullException(nameof(palette)); this.paletteVector = new Vector4[this.Palette.Length]; - PixelOperations.Instance.ToScaledVector4(this.Palette, this.paletteVector, this.Palette.Length); + PixelOperations.Instance.ToScaledVector4(this.Palette, this.paletteVector); } /// diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs index 6e594f223e..bc0ed0eab1 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization // Collect the palette. Required before the second pass runs. TPixel[] palette = this.GetPalette(); this.paletteVector = new Vector4[palette.Length]; - PixelOperations.Instance.ToScaledVector4(palette, this.paletteVector, palette.Length); + PixelOperations.Instance.ToScaledVector4(palette, this.paletteVector); var quantizedFrame = new QuantizedFrame(image.MemoryAllocator, width, height, palette); if (this.Dither) diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs index cdf3514e2d..625400413d 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization Guard.MustBeBetweenOrEqualTo(colors.Length, 1, 256, nameof(colors)); this.palette = colors; this.paletteVector = new Vector4[this.palette.Length]; - PixelOperations.Instance.ToScaledVector4(this.palette, this.paletteVector, this.palette.Length); + PixelOperations.Instance.ToScaledVector4(this.palette, this.paletteVector); } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 5bd61aab19..05c4464f18 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -257,7 +257,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Span sourceRow = source.GetPixelRowSpan(y); Span tempRowSpan = tempRowBuffer.Span; - PixelOperations.Instance.ToVector4(sourceRow, tempRowSpan, sourceRow.Length); + PixelOperations.Instance.ToVector4(sourceRow, tempRowSpan); Vector4Utils.Premultiply(tempRowSpan); ref Vector4 firstPassBaseRef = ref firstPassPixelsTransposed.Span[y]; @@ -309,7 +309,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } Span targetRowSpan = destination.GetPixelRowSpan(y); - PixelOperations.Instance.FromVector4(tempRowSpan, targetRowSpan, tempRowSpan.Length); + PixelOperations.Instance.FromVector4(tempRowSpan, targetRowSpan); } }); } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 958c4744ad..0082e6c0ec 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -269,7 +269,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { this.Measure( times, - () => PixelOperations.Instance.ToVector4(source.GetSpan(), dest.GetSpan(), count)); + () => PixelOperations.Instance.ToVector4(source.GetSpan(), dest.GetSpan())); } } } @@ -367,7 +367,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromVector4(s, d.GetSpan(), count) + (s, d) => Operations.FromVector4(s, d.GetSpan()) ); } @@ -381,7 +381,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromScaledVector4(s, d.GetSpan(), count) + (s, d) => Operations.FromScaledVector4(s, d.GetSpan()) ); } @@ -417,7 +417,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToVector4(s, d.GetSpan(), count) + (s, d) => Operations.ToVector4(s, d.GetSpan()) ); } @@ -431,7 +431,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToScaledVector4(s, d.GetSpan(), count) + (s, d) => Operations.ToScaledVector4(s, d.GetSpan()) ); } diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index 78927dece3..f055ce5480 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Tests { Span pixelSpan = frame.GetPixelSpan(); - PixelOperations.Instance.ToScaledVector4(pixelSpan, tempSpan, pixelSpan.Length); + PixelOperations.Instance.ToScaledVector4(pixelSpan, tempSpan); for (int i = 0; i < tempSpan.Length; i++) { @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Tests v.W = 1F; } - PixelOperations.Instance.FromScaledVector4(tempSpan, pixelSpan, pixelSpan.Length); + PixelOperations.Instance.FromScaledVector4(tempSpan, pixelSpan); } } }); From 6e52e99f3725fbf89ac1b5fc288f18ac70370d1d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 17:25:12 +0200 Subject: [PATCH 207/381] Adapt Span.CopyTo(...) semantics for all pixel conversion methods in PixelOperations --- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 2 +- .../Encoder/YCbCrForwardConverter{TPixel}.cs | 4 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 8 +- src/ImageSharp/ImageFrame{TPixel}.cs | 2 +- .../Argb32.PixelOperations.Generated.cs | 60 ++--- .../Bgr24.PixelOperations.Generated.cs | 60 ++--- .../Bgra32.PixelOperations.Generated.cs | 60 ++--- .../Gray16.PixelOperations.Generated.cs | 60 ++--- .../Gray8.PixelOperations.Generated.cs | 60 ++--- .../Rgb24.PixelOperations.Generated.cs | 60 ++--- .../Rgb48.PixelOperations.Generated.cs | 60 ++--- .../Rgba32.PixelOperations.Generated.cs | 60 ++--- .../Rgba64.PixelOperations.Generated.cs | 60 ++--- .../Generated/_Common.ttinclude | 18 +- .../PixelOperations{TPixel}.Generated.cs | 234 ++++++++---------- .../PixelOperations{TPixel}.Generated.tt | 26 +- .../PixelFormats/PixelOperations{TPixel}.cs | 20 +- .../Quantization/WuFrameQuantizer{TPixel}.cs | 2 +- .../Color/Bulk/FromVector4.cs | 4 +- .../Color/Bulk/ToVector4.cs | 4 +- .../PixelBlenders/PorterDuffBulkVsPixel.cs | 6 +- .../ImageComparison/ExactImageComparer.cs | 4 +- .../ImageComparison/TolerantImageComparer.cs | 4 +- .../ReferenceCodecs/SystemDrawingBridge.cs | 6 +- 24 files changed, 433 insertions(+), 451 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index f00a6b61e3..7db347aa65 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -217,7 +217,7 @@ namespace SixLabors.ImageSharp.Formats.Gif { Span rgbaSpan = rgbaBuffer.GetSpan(); ref Rgba32 paletteRef = ref MemoryMarshal.GetReference(rgbaSpan); - PixelOperations.Instance.ToRgba32(quantized.Palette, rgbaSpan, length); + PixelOperations.Instance.ToRgba32(quantized.Palette, rgbaSpan); for (int i = quantized.Palette.Length - 1; i >= 0; i--) { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs index 311ffed24b..b2a8fccf4a 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder /// On-stack worker struct to efficiently encapsulate the TPixel -> Rgb24 -> YCbCr conversion chain of 8x8 pixel blocks. /// /// The pixel type to work on - internal struct YCbCrForwardConverter + internal ref struct YCbCrForwardConverter where TPixel : struct, IPixel { /// @@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder this.pixelBlock.LoadAndStretchEdges(pixels, x, y); Span rgbSpan = this.rgbBlock.AsSpanUnsafe(); - PixelOperations.Instance.ToRgb24(this.pixelBlock.AsSpanUnsafe(), rgbSpan, 64); + PixelOperations.Instance.ToRgb24(this.pixelBlock.AsSpanUnsafe(), rgbSpan); ref float yBlockStart = ref Unsafe.As(ref this.Y); ref float cbBlockStart = ref Unsafe.As(ref this.Cb); diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index cf7b7b2c66..84f7cb6cc4 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -327,7 +327,7 @@ namespace SixLabors.ImageSharp.Formats.Png { Span luminanceSpan = luminanceBuffer.GetSpan(); ref Gray16 luminanceRef = ref MemoryMarshal.GetReference(luminanceSpan); - PixelOperations.Instance.ToGray16(rowSpan, luminanceSpan, rowSpan.Length); + PixelOperations.Instance.ToGray16(rowSpan, luminanceSpan); // Can't map directly to byte array as it's big endian. for (int x = 0, o = 0; x < luminanceSpan.Length; x++, o += 2) @@ -370,7 +370,7 @@ namespace SixLabors.ImageSharp.Formats.Png { Span rgbaSpan = rgbaBuffer.GetSpan(); ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan); - PixelOperations.Instance.ToRgba64(rowSpan, rgbaSpan, rowSpan.Length); + PixelOperations.Instance.ToRgba64(rowSpan, rgbaSpan); // Can't map directly to byte array as it's big endian. for (int x = 0, o = 0; x < rgbaSpan.Length; x++, o += 4) @@ -430,7 +430,7 @@ namespace SixLabors.ImageSharp.Formats.Png { Span rgbaSpan = rgbaBuffer.GetSpan(); ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan); - PixelOperations.Instance.ToRgba64(rowSpan, rgbaSpan, rowSpan.Length); + PixelOperations.Instance.ToRgba64(rowSpan, rgbaSpan); // Can't map directly to byte array as it's big endian. for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 8) @@ -453,7 +453,7 @@ namespace SixLabors.ImageSharp.Formats.Png { Span rgbSpan = rgbBuffer.GetSpan(); ref Rgb48 rgbRef = ref MemoryMarshal.GetReference(rgbSpan); - PixelOperations.Instance.ToRgb48(rowSpan, rgbSpan, rowSpan.Length); + PixelOperations.Instance.ToRgb48(rowSpan, rgbSpan); // Can't map directly to byte array as it's big endian. for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 6) diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index ecf9e13ceb..25c517d442 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -296,7 +296,7 @@ namespace SixLabors.ImageSharp { Span sourceRow = this.GetPixelRowSpan(y); Span targetRow = target.GetPixelRowSpan(y); - PixelOperations.Instance.To(sourceRow, targetRow, sourceRow.Length); + PixelOperations.Instance.To(sourceRow, targetRow); } }); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs index 655c4c3188..26e85e043d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs @@ -22,31 +22,31 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromArgb32(ReadOnlySpan source, Span destPixels, int count) + internal override void FromArgb32(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); - source.Slice(0, count).CopyTo(destPixels); + source.CopyTo(destPixels); } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - sourcePixels.Slice(0, count).CopyTo(destPixels); + sourcePixels.CopyTo(destPixels); } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); @@ -56,14 +56,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); @@ -73,14 +73,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); @@ -90,14 +90,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); @@ -107,14 +107,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); @@ -124,14 +124,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); @@ -141,14 +141,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); @@ -158,14 +158,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs index 5d2ca335e5..080a25429b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs @@ -22,31 +22,31 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromBgr24(ReadOnlySpan source, Span destPixels, int count) + internal override void FromBgr24(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); - source.Slice(0, count).CopyTo(destPixels); + source.CopyTo(destPixels); } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - sourcePixels.Slice(0, count).CopyTo(destPixels); + sourcePixels.CopyTo(destPixels); } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); @@ -56,14 +56,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); @@ -73,14 +73,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); @@ -90,14 +90,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); @@ -107,14 +107,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); @@ -124,14 +124,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); @@ -141,14 +141,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); @@ -158,14 +158,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs index 1121f43437..6a1bb6cdc3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs @@ -22,31 +22,31 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromBgra32(ReadOnlySpan source, Span destPixels, int count) + internal override void FromBgra32(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); - source.Slice(0, count).CopyTo(destPixels); + source.CopyTo(destPixels); } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - sourcePixels.Slice(0, count).CopyTo(destPixels); + sourcePixels.CopyTo(destPixels); } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); @@ -56,14 +56,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); @@ -73,14 +73,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); @@ -90,14 +90,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); @@ -107,14 +107,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); @@ -124,14 +124,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); @@ -141,14 +141,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); @@ -158,14 +158,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs index e27f8bc587..cbb9df4459 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs @@ -22,31 +22,31 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromGray16(ReadOnlySpan source, Span destPixels, int count) + internal override void FromGray16(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); - source.Slice(0, count).CopyTo(destPixels); + source.CopyTo(destPixels); } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - sourcePixels.Slice(0, count).CopyTo(destPixels); + sourcePixels.CopyTo(destPixels); } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); @@ -56,14 +56,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); @@ -73,14 +73,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); @@ -90,14 +90,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); @@ -107,14 +107,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); @@ -124,14 +124,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); @@ -141,14 +141,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); @@ -158,14 +158,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs index 26ed91cfff..b88f18e8de 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs @@ -22,31 +22,31 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromGray8(ReadOnlySpan source, Span destPixels, int count) + internal override void FromGray8(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); - source.Slice(0, count).CopyTo(destPixels); + source.CopyTo(destPixels); } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - sourcePixels.Slice(0, count).CopyTo(destPixels); + sourcePixels.CopyTo(destPixels); } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); @@ -56,14 +56,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); @@ -73,14 +73,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); @@ -90,14 +90,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); @@ -107,14 +107,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); @@ -124,14 +124,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); @@ -141,14 +141,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); @@ -158,14 +158,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs index 8a6c6bddc1..49c56f4fa2 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs @@ -22,31 +22,31 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromRgb24(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgb24(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); - source.Slice(0, count).CopyTo(destPixels); + source.CopyTo(destPixels); } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - sourcePixels.Slice(0, count).CopyTo(destPixels); + sourcePixels.CopyTo(destPixels); } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); @@ -56,14 +56,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); @@ -73,14 +73,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); @@ -90,14 +90,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); @@ -107,14 +107,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); @@ -124,14 +124,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); @@ -141,14 +141,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); @@ -158,14 +158,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs index 1701109edf..cda6dbf72c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs @@ -22,31 +22,31 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromRgb48(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgb48(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); - source.Slice(0, count).CopyTo(destPixels); + source.CopyTo(destPixels); } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - sourcePixels.Slice(0, count).CopyTo(destPixels); + sourcePixels.CopyTo(destPixels); } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); @@ -56,14 +56,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); @@ -73,14 +73,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); @@ -90,14 +90,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); @@ -107,14 +107,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); @@ -124,14 +124,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); @@ -141,14 +141,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); @@ -158,14 +158,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs index fb817a29ae..ab264f8701 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs @@ -22,31 +22,31 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromRgba32(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgba32(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); - source.Slice(0, count).CopyTo(destPixels); + source.CopyTo(destPixels); } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - sourcePixels.Slice(0, count).CopyTo(destPixels); + sourcePixels.CopyTo(destPixels); } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); @@ -56,14 +56,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); @@ -73,14 +73,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); @@ -90,14 +90,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); @@ -107,14 +107,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); @@ -124,14 +124,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); @@ -141,14 +141,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); @@ -158,14 +158,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs index d49fb7ae5e..4bc6b101ae 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs @@ -22,31 +22,31 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromRgba64(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgba64(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); - source.Slice(0, count).CopyTo(destPixels); + source.CopyTo(destPixels); } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - sourcePixels.Slice(0, count).CopyTo(destPixels); + sourcePixels.CopyTo(destPixels); } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); @@ -56,14 +56,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); @@ -73,14 +73,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); @@ -90,14 +90,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); @@ -107,14 +107,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); @@ -124,14 +124,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); @@ -141,14 +141,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); @@ -158,14 +158,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude index af8c42357e..176075a40f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude @@ -19,19 +19,19 @@ using System.Runtime.InteropServices; #> /// - internal override void From<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destPixels, int count) + internal override void From<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); - source.Slice(0, count).CopyTo(destPixels); + source.CopyTo(destPixels); } /// - internal override void To<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<<#=pixelType#>> destPixels, int count) + internal override void To<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<<#=pixelType#>> destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - sourcePixels.Slice(0, count).CopyTo(destPixels); + sourcePixels.CopyTo(destPixels); } <#+ @@ -42,14 +42,14 @@ using System.Runtime.InteropServices; #> /// - internal override void To<#=toPixelType#>(ReadOnlySpan<<#=fromPixelType#>> sourcePixels, Span<<#=toPixelType#>> destPixels, int count) + internal override void To<#=toPixelType#>(ReadOnlySpan<<#=fromPixelType#>> sourcePixels, Span<<#=toPixelType#>> destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref <#=fromPixelType#> sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref <#=toPixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref <#=fromPixelType#> sp = ref Unsafe.Add(ref sourceRef, i); ref <#=toPixelType#> dp = ref Unsafe.Add(ref destRef, i); diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs index f1d426389b..1cbf487d76 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs @@ -11,19 +11,18 @@ namespace SixLabors.ImageSharp.PixelFormats public partial class PixelOperations { /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts all pixels in 'source` span of into a span of -s. /// /// The source of data. /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void FromArgb32(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromArgb32(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); ref Argb32 sourceBaseRef = ref MemoryMarshal.GetReference(source); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < source.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); @@ -33,7 +32,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// 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. @@ -42,23 +41,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void FromArgb32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromArgb32(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromArgb32(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// /// The span of source pixels /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal virtual void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Argb32 dp = ref Unsafe.Add(ref destBaseRef, i); @@ -68,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source pixels. @@ -77,23 +75,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToArgb32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToArgb32(sourcePixels, MemoryMarshal.Cast(destBytes), count); + this.ToArgb32(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts all pixels in 'source` span of into a span of -s. /// /// The source of data. /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void FromBgr24(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromBgr24(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); ref Bgr24 sourceBaseRef = ref MemoryMarshal.GetReference(source); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < source.Length; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); @@ -103,7 +100,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// 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. @@ -112,23 +109,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void FromBgr24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromBgr24(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromBgr24(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// /// The span of source pixels /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal virtual void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i); @@ -138,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source pixels. @@ -147,23 +143,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToBgr24Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToBgr24(sourcePixels, MemoryMarshal.Cast(destBytes), count); + this.ToBgr24(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts all pixels in 'source` span of into a span of -s. /// /// The source of data. /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void FromBgra32(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromBgra32(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); ref Bgra32 sourceBaseRef = ref MemoryMarshal.GetReference(source); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < source.Length; i++) { ref Bgra32 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); @@ -173,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// 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. @@ -182,23 +177,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void FromBgra32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromBgra32(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromBgra32(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// /// The span of source pixels /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal virtual void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i); @@ -208,7 +202,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source pixels. @@ -217,23 +211,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToBgra32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToBgra32(sourcePixels, MemoryMarshal.Cast(destBytes), count); + this.ToBgra32(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts all pixels in 'source` span of into a span of -s. /// /// The source of data. /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void FromGray8(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromGray8(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); ref Gray8 sourceBaseRef = ref MemoryMarshal.GetReference(source); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < source.Length; i++) { ref Gray8 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); @@ -243,7 +236,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// 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. @@ -252,23 +245,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void FromGray8Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromGray8(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromGray8(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// /// The span of source pixels /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal virtual void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray8 destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Gray8 dp = ref Unsafe.Add(ref destBaseRef, i); @@ -278,7 +270,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source pixels. @@ -287,23 +279,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToGray8Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToGray8(sourcePixels, MemoryMarshal.Cast(destBytes), count); + this.ToGray8(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts all pixels in 'source` span of into a span of -s. /// /// The source of data. /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void FromGray16(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromGray16(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); ref Gray16 sourceBaseRef = ref MemoryMarshal.GetReference(source); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < source.Length; i++) { ref Gray16 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); @@ -313,7 +304,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// 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. @@ -322,23 +313,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void FromGray16Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromGray16(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromGray16(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// /// The span of source pixels /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal virtual void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray16 destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Gray16 dp = ref Unsafe.Add(ref destBaseRef, i); @@ -348,7 +338,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source pixels. @@ -357,23 +347,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToGray16Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToGray16(sourcePixels, MemoryMarshal.Cast(destBytes), count); + this.ToGray16(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts all pixels in 'source` span of into a span of -s. /// /// The source of data. /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void FromRgb24(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromRgb24(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); ref Rgb24 sourceBaseRef = ref MemoryMarshal.GetReference(source); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < source.Length; i++) { ref Rgb24 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); @@ -383,7 +372,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// 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. @@ -392,23 +381,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void FromRgb24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromRgb24(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromRgb24(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// /// The span of source pixels /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal virtual void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destBaseRef, i); @@ -418,7 +406,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source pixels. @@ -427,23 +415,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgb24Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgb24(sourcePixels, MemoryMarshal.Cast(destBytes), count); + this.ToRgb24(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts all pixels in 'source` span of into a span of -s. /// /// The source of data. /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void FromRgba32(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromRgba32(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); ref Rgba32 sourceBaseRef = ref MemoryMarshal.GetReference(source); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < source.Length; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); @@ -453,7 +440,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// 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. @@ -462,23 +449,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void FromRgba32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromRgba32(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromRgba32(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// /// The span of source pixels /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal virtual void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i); @@ -488,7 +474,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source pixels. @@ -497,23 +483,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgba32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgba32(sourcePixels, MemoryMarshal.Cast(destBytes), count); + this.ToRgba32(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts all pixels in 'source` span of into a span of -s. /// /// The source of data. /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void FromRgb48(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromRgb48(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); ref Rgb48 sourceBaseRef = ref MemoryMarshal.GetReference(source); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < source.Length; i++) { ref Rgb48 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); @@ -523,7 +508,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// 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. @@ -532,23 +517,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void FromRgb48Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromRgb48(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromRgb48(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// /// The span of source pixels /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal virtual void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destBaseRef, i); @@ -558,7 +542,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source pixels. @@ -567,23 +551,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgb48Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgb48(sourcePixels, MemoryMarshal.Cast(destBytes), count); + this.ToRgb48(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts all pixels in 'source` span of into a span of -s. /// /// The source of data. /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void FromRgba64(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromRgba64(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); ref Rgba64 sourceBaseRef = ref MemoryMarshal.GetReference(source); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < source.Length; i++) { ref Rgba64 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); @@ -593,7 +576,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// 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. @@ -602,23 +585,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void FromRgba64Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromRgba64(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromRgba64(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// /// The span of source pixels /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal virtual void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destBaseRef, i); @@ -628,7 +610,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source pixels. @@ -637,7 +619,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgba64Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgba64(sourcePixels, MemoryMarshal.Cast(destBytes), count); + this.ToRgba64(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt index 723b0358fe..484dde9ac0 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt @@ -16,19 +16,18 @@ #> /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts all pixels in 'source` span of into a span of -s. /// /// The source of data. /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void From<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) + internal virtual void From<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); ref <#=pixelType#> sourceBaseRef = ref MemoryMarshal.GetReference(source); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < source.Length; i++) { ref <#=pixelType#> sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); @@ -38,7 +37,7 @@ } /// - /// A helper for that expects a byte span. + /// 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. @@ -47,7 +46,7 @@ [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void From<#=pixelType#>Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.From<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); + this.From<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes).Slice(0, count), destPixels); } <# @@ -57,19 +56,18 @@ { #> /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// /// The span of source pixels /// The destination span of data. - /// The number of pixels to convert. - internal virtual void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + internal virtual void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref <#=pixelType#> destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destBaseRef, i); @@ -79,7 +77,7 @@ } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source pixels. @@ -88,7 +86,7 @@ [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void To<#=pixelType#>Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.To<#=pixelType#>(sourcePixels, MemoryMarshal.Cast>(destBytes), count); + this.To<#=pixelType#>(sourcePixels.Slice(count), MemoryMarshal.Cast>(destBytes)); } <# } diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index e6ccaf914d..510645c4e9 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static PixelOperations Instance { get; } = default(TPixel).CreatePixelOperations(); /// - /// Bulk version of + /// Bulk version of converting 'sourceVectors.Length' pixels into 'destinationColors'. /// /// The to the source vectors. /// The to the destination colors. @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// Bulk version of . + /// Bulk version of converting 'sourceColors.Length' pixels into 'destinationVectors'. /// /// The to the source colors. /// The to the destination vectors. @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// Bulk version of + /// Bulk version of converting 'sourceVectors.Length' pixels into 'destinationColors'. /// /// The to the source vectors. /// The to the destination colors. @@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// Bulk version of . + /// Bulk version of converting 'sourceColors.Length' pixels into 'destinationVectors'. /// /// The to the source colors. /// The to the destination vectors. @@ -102,17 +102,19 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// Performs a bulk conversion of a collection of one pixel format into another. + /// Converts 'sourceColors.Length' pixels from 'sourceColors' into 'destinationColors'. /// - /// The pixel format. + /// The destination pixel type. /// The to the source colors. /// The to the destination colors. - /// The number of pixels to convert. - internal virtual void To(ReadOnlySpan sourceColors, Span destinationColors, int count) + internal virtual void To( + ReadOnlySpan sourceColors, + Span destinationColors) where TDestinationPixel : struct, IPixel { - GuardSpans(sourceColors, nameof(sourceColors), destinationColors, nameof(destinationColors), count); + Guard.DestinationShouldNotBeTooShort(sourceColors, destinationColors, nameof(destinationColors)); + int count = sourceColors.Length; ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); // Gray8 and Gray16 are special implementations of IPixel in that they do not conform to the diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index dd947f337d..98a5d5eb51 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -448,7 +448,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { Span row = source.GetPixelRowSpan(y); Span rgbaSpan = rgbaBuffer.GetSpan(); - PixelOperations.Instance.ToRgba32(row, rgbaSpan, source.Width); + PixelOperations.Instance.ToRgba32(row, rgbaSpan); ref Rgba32 scanBaseRef = ref MemoryMarshal.GetReference(rgbaSpan); // And loop through each column diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs index 72322f0d44..1cd8c0196b 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs @@ -59,13 +59,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Benchmark] public void PixelOperations_Base() { - new PixelOperations().FromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + new PixelOperations().FromVector4(this.source.GetSpan(), this.destination.GetSpan()); } [Benchmark] public void PixelOperations_Specialized() { - PixelOperations.Instance.FromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + PixelOperations.Instance.FromVector4(this.source.GetSpan(), this.destination.GetSpan()); } } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 2cbe549e4a..e313953a6c 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -65,13 +65,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Benchmark] public void PixelOperations_Base() { - new PixelOperations().ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + new PixelOperations().ToVector4(this.source.GetSpan(), this.destination.GetSpan()); } [Benchmark] public void PixelOperations_Specialized() { - PixelOperations.Instance.ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + PixelOperations.Instance.ToVector4(this.source.GetSpan(), this.destination.GetSpan()); } } diff --git a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs index 46b58f369d..051646f90b 100644 --- a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs +++ b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs @@ -35,15 +35,15 @@ namespace SixLabors.ImageSharp.Benchmarks 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.ToVector4(background, backgroundSpan); + PixelOperations.Instance.ToVector4(source, sourceSpan); for (int i = 0; i < destination.Length; i++) { destinationSpan[i] = PorterDuffFunctions.NormalSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); } - PixelOperations.Instance.FromVector4(destinationSpan, destination, destination.Length); + PixelOperations.Instance.FromVector4(destinationSpan, destination); } } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs index 8dca11caeb..886e02c139 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs @@ -34,8 +34,8 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison Span aSpan = expected.GetPixelRowSpan(y); Span bSpan = actual.GetPixelRowSpan(y); - PixelOperations.Instance.ToRgba64(aSpan, aBuffer, width); - PixelOperations.Instance.ToRgba64(bSpan, bBuffer, width); + PixelOperations.Instance.ToRgba64(aSpan, aBuffer); + PixelOperations.Instance.ToRgba64(bSpan, bBuffer); for (int x = 0; x < width; x++) { diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs index 674603380f..9563edbb58 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs @@ -80,8 +80,8 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison Span aSpan = expected.GetPixelRowSpan(y); Span bSpan = actual.GetPixelRowSpan(y); - PixelOperations.Instance.ToRgba64(aSpan, aBuffer, width); - PixelOperations.Instance.ToRgba64(bSpan, bBuffer, width); + PixelOperations.Instance.ToRgba64(aSpan, aBuffer); + PixelOperations.Instance.ToRgba64(bSpan, bBuffer); for (int x = 0; x < width; x++) { diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs index 1543e2c8f4..03b77149be 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs @@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); - PixelOperations.Instance.FromBgra32(workBuffer.GetSpan(), row, row.Length); + PixelOperations.Instance.FromBgra32(workBuffer.GetSpan().Slice(0, w), row); } } } @@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); - PixelOperations.Instance.FromBgr24(workBuffer.GetSpan(), row, row.Length); + PixelOperations.Instance.FromBgr24(workBuffer.GetSpan().Slice(w), row); } } } @@ -130,7 +130,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs for (int y = 0; y < h; y++) { Span row = image.Frames.RootFrame.GetPixelRowSpan(y); - PixelOperations.Instance.ToBgra32(row, workBuffer.GetSpan(), row.Length); + PixelOperations.Instance.ToBgra32(row, workBuffer.GetSpan()); byte* destPtr = destPtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); From b69baf57f445b05d44b24727bbd1918ca3d9ed61 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 17:39:02 +0200 Subject: [PATCH 208/381] fix span length issues related to Vector4 conversion --- src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs | 12 ++++++------ .../Processors/Convolution/Convolution2DProcessor.cs | 4 ++-- .../Convolution/Convolution2PassProcessor.cs | 4 ++-- .../Processors/Convolution/ConvolutionProcessor.cs | 4 ++-- .../Quantization/FrameQuantizerBase{TPixel}.cs | 2 +- tests/ImageSharp.Tests/Issues/Issue412.cs | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs index 6c24ce05b2..6f0bba5cf9 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.ToScaledVector4(background, backgroundSpan); - PixelOperations.Instance.ToScaledVector4(source, sourceSpan); + PixelOperations.Instance.ToScaledVector4(background.Slice(0, background.Length), backgroundSpan); + PixelOperations.Instance.ToScaledVector4(source.Slice(0, background.Length), sourceSpan); this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); - PixelOperations.Instance.FromScaledVector4(destinationSpan, destination); + PixelOperations.Instance.FromScaledVector4(destinationSpan.Slice(0, background.Length), destination); } } @@ -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.ToScaledVector4(background, backgroundSpan); - PixelOperations.Instance.ToScaledVector4(source, sourceSpan); + PixelOperations.Instance.ToScaledVector4(background.Slice(0, background.Length), backgroundSpan); + PixelOperations.Instance.ToScaledVector4(source.Slice(0, background.Length), sourceSpan); this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); - PixelOperations.Instance.FromScaledVector4(destinationSpan, destination); + PixelOperations.Instance.FromScaledVector4(destinationSpan.Slice(0, background.Length), destination); } } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs index 90049a994d..a26fe6bfd1 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs @@ -75,14 +75,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan); + PixelOperations.Instance.ToVector4(targetRowSpan.Slice(0, length), vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve2D(in matrixY, in matrixX, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan); + PixelOperations.Instance.FromVector4(vectorSpan.Slice(0, length), targetRowSpan); } }); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs index f38f16f1a9..98accb6061 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs @@ -93,14 +93,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan); + PixelOperations.Instance.ToVector4(targetRowSpan.Slice(0, length), vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve(in matrix, sourcePixels, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan); + PixelOperations.Instance.FromVector4(vectorSpan.Slice(0, length), targetRowSpan); } }); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs index d1b3f0ccf8..dcecf2b827 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs @@ -59,14 +59,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan); + PixelOperations.Instance.ToVector4(targetRowSpan.Slice(0, length), vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve(in matrix, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan); + PixelOperations.Instance.FromVector4(vectorSpan.Slice(0, length), targetRowSpan); } }); diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs index bc0ed0eab1..71999576be 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public virtual QuantizedFrame QuantizeFrame(ImageFrame image) { Guard.NotNull(image, nameof(image)); - + // Get the size of the source image int height = image.Height; int width = image.Width; diff --git a/tests/ImageSharp.Tests/Issues/Issue412.cs b/tests/ImageSharp.Tests/Issues/Issue412.cs index 6123c822b8..b0374ce1fa 100644 --- a/tests/ImageSharp.Tests/Issues/Issue412.cs +++ b/tests/ImageSharp.Tests/Issues/Issue412.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.Issues [WithBlankImages(40, 30, PixelTypes.Rgba32)] public void AllPixelsExpectedToBeRedWhenAntialiasedDisabled(TestImageProvider provider) where TPixel : struct, IPixel { - using (var image = provider.GetImage()) + using (Image image = provider.GetImage()) { image.Mutate( context => From 30994e7640bfc0a4c0360e4dd97e5396669927d8 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 18:03:47 +0200 Subject: [PATCH 209/381] fix wrong Slice() usages --- .../PixelOperations{TPixel}.Generated.cs | 18 +++++++++--------- .../PixelOperations{TPixel}.Generated.tt | 2 +- .../Quantization/FrameQuantizerBase{TPixel}.cs | 2 +- .../ReferenceCodecs/SystemDrawingBridge.cs | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs index 1cbf487d76..07ecf87569 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToArgb32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToArgb32(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); + this.ToArgb32(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// @@ -143,7 +143,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToBgr24Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToBgr24(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); + this.ToBgr24(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// @@ -211,7 +211,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToBgra32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToBgra32(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); + this.ToBgra32(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// @@ -279,7 +279,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToGray8Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToGray8(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); + this.ToGray8(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// @@ -347,7 +347,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToGray16Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToGray16(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); + this.ToGray16(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// @@ -415,7 +415,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgb24Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgb24(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); + this.ToRgb24(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// @@ -483,7 +483,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgba32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgba32(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); + this.ToRgba32(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// @@ -551,7 +551,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgb48Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgb48(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); + this.ToRgb48(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// @@ -619,7 +619,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgba64Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgba64(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); + this.ToRgba64(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt index 484dde9ac0..ef73378a24 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt @@ -86,7 +86,7 @@ [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void To<#=pixelType#>Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.To<#=pixelType#>(sourcePixels.Slice(count), MemoryMarshal.Cast>(destBytes)); + this.To<#=pixelType#>(sourcePixels.Slice(0, count), MemoryMarshal.Cast>(destBytes)); } <# } diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs index 71999576be..bc0ed0eab1 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public virtual QuantizedFrame QuantizeFrame(ImageFrame image) { Guard.NotNull(image, nameof(image)); - + // Get the size of the source image int height = image.Height; int width = image.Width; diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs index 03b77149be..e96825db1c 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs @@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); - PixelOperations.Instance.FromBgr24(workBuffer.GetSpan().Slice(w), row); + PixelOperations.Instance.FromBgr24(workBuffer.GetSpan().Slice(0, w), row); } } } From cd543b24e78511e2d2b23d3a10a269cf0d43d663 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 22 Oct 2018 18:17:09 +0100 Subject: [PATCH 210/381] Bump build now Github should be returned to normal. --- .../TestUtilities/TestDataGenerator.cs | 47 +++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs index 912b86e347..56cde41fc1 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs @@ -1,10 +1,24 @@ -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; using System.Numerics; namespace SixLabors.ImageSharp.Tests { + /// + /// Helper methods that allow the creation of random test data. + /// internal static class TestDataGenerator { + /// + /// Creates an of the given length consisting of random values between the two ranges. + /// + /// The pseudo-random number generator. + /// The length. + /// The minimum value. + /// The maximum value. + /// The . public static float[] GenerateRandomFloatArray(this Random rnd, int length, float minVal, float maxVal) { float[] values = new float[length]; @@ -17,6 +31,14 @@ namespace SixLabors.ImageSharp.Tests return values; } + /// + /// Creates an of the given length consisting of random values between the two ranges. + /// + /// The pseudo-random number generator. + /// The length. + /// The minimum value. + /// The maximum value. + /// The . public static Vector4[] GenerateRandomVectorArray(this Random rnd, int length, float minVal, float maxVal) { var values = new Vector4[length]; @@ -33,20 +55,32 @@ namespace SixLabors.ImageSharp.Tests return values; } + /// + /// Creates an of the given length consisting of rounded random values between the two ranges. + /// + /// The pseudo-random number generator. + /// The length. + /// The minimum value. + /// The maximum value. + /// The . public static float[] GenerateRandomRoundedFloatArray(this Random rnd, int length, float minVal, float maxVal) { float[] values = new float[length]; for (int i = 0; i < length; i++) { - values[i] = (float) Math.Round(rnd.GetRandomFloat(minVal, maxVal)); + values[i] = (float)Math.Round(rnd.GetRandomFloat(minVal, maxVal)); } return values; } - - + /// + /// Creates an of the given length consisting of random values. + /// + /// The pseudo-random number generator. + /// The length. + /// The . public static byte[] GenerateRandomByteArray(this Random rnd, int length) { byte[] values = new byte[length]; @@ -54,9 +88,6 @@ namespace SixLabors.ImageSharp.Tests return values; } - private static float GetRandomFloat(this Random rnd, float minVal, float maxVal) - { - return (float)rnd.NextDouble() * (maxVal - minVal) + minVal; - } + private static float GetRandomFloat(this Random rnd, float minVal, float maxVal) => ((float)rnd.NextDouble() * (maxVal - minVal)) + minVal; } } \ No newline at end of file From ca60ecf7f4564af0fafdbde62759a39d60a01a06 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 23 Oct 2018 01:11:14 +0200 Subject: [PATCH 211/381] pass Configuration to Vector4 converters in PixelOperations --- .../Processing/BrushApplicator.cs | 2 +- .../Processing/ImageBrush{TPixel}.cs | 7 +- .../Processing/PatternBrush{TPixel}.cs | 7 +- .../Processors/Drawing/DrawImageProcessor.cs | 4 +- .../Processing/RecolorBrush{TPixel}.cs | 7 +- .../Processing/SolidBrush{TPixel}.cs | 10 ++- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 17 ++-- .../Decoder/JpegImagePostProcessor.cs | 12 ++- .../Formats/Jpeg/JpegDecoderCore.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 3 +- src/ImageSharp/ImageFrame{TPixel}.cs | 16 ++-- .../PixelFormats/PixelBlender{TPixel}.cs | 81 ++++++++++++++----- .../Rgba32.PixelOperations.cs | 20 +++-- .../RgbaVector.PixelOperations.cs | 9 ++- .../PixelFormats/PixelOperations{TPixel}.cs | 28 ++++++- .../Convolution/Convolution2DProcessor.cs | 4 +- .../Convolution/Convolution2PassProcessor.cs | 4 +- .../Convolution/ConvolutionProcessor.cs | 4 +- .../Dithering/PaletteDitherProcessorBase.cs | 19 ++++- .../Overlays/BackgroundColorProcessor.cs | 2 +- .../Processors/Overlays/GlowProcessor.cs | 2 +- .../Processors/Overlays/VignetteProcessor.cs | 2 +- .../FrameQuantizerBase{TPixel}.cs | 4 +- .../Processors/Quantization/IQuantizer.cs | 6 +- .../Quantization/OctreeQuantizer.cs | 5 +- .../PaletteFrameQuantizer{TPixel}.cs | 5 +- .../Quantization/PaletteQuantizer.cs | 15 ++-- .../Quantization/QuantizeProcessor.cs | 2 +- .../Processors/Quantization/WuQuantizer.cs | 5 +- .../Processors/Transforms/ResizeProcessor.cs | 4 +- .../Color/Bulk/FromVector4.cs | 10 ++- .../Color/Bulk/ToVector4.cs | 25 +++--- .../PixelBlenders/PorterDuffBulkVsPixel.cs | 8 +- .../Jpg/JpegImagePostProcessorTests.cs | 4 +- .../PorterDuffFunctionsTests_TPixel.cs | 20 ++--- .../PixelFormats/PixelOperationsTests.cs | 15 ++-- .../Quantization/QuantizedImageTests.cs | 25 ++++-- .../TestUtilities/TestImageExtensions.cs | 36 +++++---- 38 files changed, 301 insertions(+), 150 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/BrushApplicator.cs b/src/ImageSharp.Drawing/Processing/BrushApplicator.cs index 770d440656..0c6e0d3b40 100644 --- a/src/ImageSharp.Drawing/Processing/BrushApplicator.cs +++ b/src/ImageSharp.Drawing/Processing/BrushApplicator.cs @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Processing } Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); - this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan); + this.Blender.Blend(this.Target.Configuration, destinationRow, destinationRow, overlaySpan, amountSpan); } } } diff --git a/src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs index c3f81868be..1ef4bb9ec9 100644 --- a/src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs @@ -140,7 +140,12 @@ namespace SixLabors.ImageSharp.Processing } Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); - this.Blender.Blend(this.source.MemoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan); + this.Blender.Blend( + this.source.Configuration, + destinationRow, + destinationRow, + overlaySpan, + amountSpan); } } } diff --git a/src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs index 2ce9a7ce57..46ed36f687 100644 --- a/src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs @@ -170,7 +170,12 @@ namespace SixLabors.ImageSharp.Processing } Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); - this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan); + this.Blender.Blend( + this.Target.Configuration, + destinationRow, + destinationRow, + overlaySpan, + amountSpan); } } } diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs index dc73420f30..0957904c62 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs @@ -79,8 +79,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing int width = maxX - minX; - MemoryAllocator memoryAllocator = this.Image.GetConfiguration().MemoryAllocator; - var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); ParallelHelper.IterateRows( @@ -93,7 +91,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing 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); + blender.Blend(configuration, background, background, foreground, this.Opacity); } }); } diff --git a/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs index 2968b68b55..09a1ff71fb 100644 --- a/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs @@ -158,7 +158,12 @@ namespace SixLabors.ImageSharp.Processing } Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); - this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan); + this.Blender.Blend( + this.Target.Configuration, + destinationRow, + destinationRow, + overlaySpan, + amountSpan); } } } diff --git a/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs index 6b69c33f07..a77c6728b5 100644 --- a/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs @@ -92,10 +92,11 @@ namespace SixLabors.ImageSharp.Processing Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); MemoryAllocator memoryAllocator = this.Target.MemoryAllocator; + Configuration configuration = this.Target.Configuration; if (this.Options.BlendPercentage == 1f) { - this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), scanline); + this.Blender.Blend(configuration, destinationRow, destinationRow, this.Colors.GetSpan(), scanline); } else { @@ -108,7 +109,12 @@ namespace SixLabors.ImageSharp.Processing amountSpan[i] = scanline[i] * this.Options.BlendPercentage; } - this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), amountSpan); + this.Blender.Blend( + configuration, + destinationRow, + destinationRow, + this.Colors.GetSpan(), + amountSpan); } } } diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 7db347aa65..81adf52ddb 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -8,6 +8,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; @@ -88,7 +89,7 @@ namespace SixLabors.ImageSharp.Formats.Gif // Quantize the image returning a palette. QuantizedFrame quantized = - this.quantizer.CreateFrameQuantizer().QuantizeFrame(image.Frames.RootFrame); + this.quantizer.CreateFrameQuantizer(image.GetConfiguration()).QuantizeFrame(image.Frames.RootFrame); // Get the number of bits. this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8); @@ -151,7 +152,7 @@ namespace SixLabors.ImageSharp.Formats.Gif else { using (QuantizedFrame paletteQuantized - = palleteQuantizer.CreateFrameQuantizer(() => quantized.Palette).QuantizeFrame(frame)) + = palleteQuantizer.CreateFrameQuantizer(image.GetConfiguration(), () => quantized.Palette).QuantizeFrame(frame)) { this.WriteImageData(paletteQuantized, stream); } @@ -171,15 +172,17 @@ namespace SixLabors.ImageSharp.Formats.Gif if (quantized is null) { // Allow each frame to be encoded at whatever color depth the frame designates if set. - if (previousFrame != null - && previousMeta.ColorTableLength != frameMetaData.ColorTableLength - && frameMetaData.ColorTableLength > 0) + if (previousFrame != null && previousMeta.ColorTableLength != frameMetaData.ColorTableLength + && frameMetaData.ColorTableLength > 0) { - quantized = this.quantizer.CreateFrameQuantizer(frameMetaData.ColorTableLength).QuantizeFrame(frame); + quantized = this.quantizer.CreateFrameQuantizer( + image.GetConfiguration(), + frameMetaData.ColorTableLength).QuantizeFrame(frame); } else { - quantized = this.quantizer.CreateFrameQuantizer().QuantizeFrame(frame); + quantized = this.quantizer.CreateFrameQuantizer(image.GetConfiguration()) + .QuantizeFrame(frame); } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs index 6bd287732d..1a6da2b2b0 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs @@ -26,6 +26,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// internal class JpegImagePostProcessor : IDisposable { + private readonly Configuration configuration; + /// /// The number of block rows to be processed in one Step. /// @@ -49,15 +51,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// /// Initializes a new instance of the class. /// - /// The to use for buffer allocations. + /// The to configure internal operations. /// The representing the uncompressed spectral Jpeg data - public JpegImagePostProcessor(MemoryAllocator memoryAllocator, IRawJpegData rawJpeg) + public JpegImagePostProcessor(Configuration configuration, IRawJpegData rawJpeg) { + this.configuration = configuration; this.RawJpeg = rawJpeg; IJpegComponent c0 = rawJpeg.Components.First(); this.NumberOfPostProcessorSteps = c0.SizeInBlocks.Height / BlockRowsPerStep; this.PostProcessorBufferSize = new Size(c0.SizeInBlocks.Width * 8, PixelRowsPerStep); + MemoryAllocator memoryAllocator = configuration.MemoryAllocator; this.ComponentProcessors = rawJpeg.Components.Select(c => new JpegComponentPostProcessor(memoryAllocator, this, c)).ToArray(); this.rgbaBuffer = memoryAllocator.Allocate(rawJpeg.ImageSizeInPixels.Width); this.colorConverter = JpegColorConverter.GetConverter(rawJpeg.ColorSpace); @@ -158,9 +162,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder this.colorConverter.ConvertToRgba(values, this.rgbaBuffer.GetSpan()); Span destRow = destination.GetPixelRowSpan(yy); - + // TODO: Investigate if slicing is actually necessary - PixelOperations.Instance.FromVector4(this.rgbaBuffer.GetSpan().Slice(0, destRow.Length), destRow); + PixelOperations.Instance.FromVector4(this.configuration, this.rgbaBuffer.GetSpan().Slice(0, destRow.Length), destRow); } } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 22d9cbdee4..36246c6820 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -936,7 +936,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg private Image PostProcessIntoImage() where TPixel : struct, IPixel { - using (var postProcessor = new JpegImagePostProcessor(this.configuration.MemoryAllocator, this)) + using (var postProcessor = new JpegImagePostProcessor(this.configuration, this)) { var image = new Image(this.configuration, this.ImageWidth, this.ImageHeight, this.MetaData); postProcessor.PostProcess(image.Frames.RootFrame); diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 84f7cb6cc4..71945d1302 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -237,7 +237,8 @@ namespace SixLabors.ImageSharp.Formats.Png } // Create quantized frame returning the palette and set the bit depth. - quantized = this.quantizer.CreateFrameQuantizer().QuantizeFrame(image.Frames.RootFrame); + quantized = this.quantizer.CreateFrameQuantizer(image.GetConfiguration()) + .QuantizeFrame(image.Frames.RootFrame); byte quantizedBits = (byte)ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8); bits = Math.Max(bits, quantizedBits); diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 25c517d442..bb95bb7b6d 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -21,7 +21,6 @@ namespace SixLabors.ImageSharp public sealed class ImageFrame : IPixelSource, IDisposable where TPixel : struct, IPixel { - private readonly Configuration configuration; private bool isDisposed; /// @@ -84,7 +83,7 @@ namespace SixLabors.ImageSharp Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); - this.configuration = configuration; + this.Configuration = configuration; this.MemoryAllocator = configuration.MemoryAllocator; this.PixelBuffer = this.MemoryAllocator.Allocate2D(width, height); this.MetaData = metaData ?? new ImageFrameMetaData(); @@ -118,7 +117,7 @@ namespace SixLabors.ImageSharp Guard.MustBeGreaterThan(height, 0, nameof(height)); Guard.NotNull(metaData, nameof(metaData)); - this.configuration = configuration; + this.Configuration = configuration; this.MemoryAllocator = configuration.MemoryAllocator; this.PixelBuffer = new Buffer2D(memorySource, width, height); this.MetaData = metaData; @@ -134,7 +133,7 @@ namespace SixLabors.ImageSharp Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(source, nameof(source)); - this.configuration = configuration; + this.Configuration = configuration; this.MemoryAllocator = configuration.MemoryAllocator; this.PixelBuffer = this.MemoryAllocator.Allocate2D(source.PixelBuffer.Width, source.PixelBuffer.Height); source.PixelBuffer.GetSpan().CopyTo(this.PixelBuffer.GetSpan()); @@ -146,6 +145,11 @@ namespace SixLabors.ImageSharp /// public MemoryAllocator MemoryAllocator { get; } + /// + /// Gets the instance associated with this . + /// + internal Configuration Configuration { get; } + /// /// Gets the image pixels. Not private as Buffer2D requires an array in its constructor. /// @@ -254,7 +258,7 @@ namespace SixLabors.ImageSharp /// Clones the current instance. /// /// The - internal ImageFrame Clone() => this.Clone(this.configuration); + internal ImageFrame Clone() => this.Clone(this.Configuration); /// /// Clones the current instance. @@ -269,7 +273,7 @@ namespace SixLabors.ImageSharp /// The pixel format. /// The internal ImageFrame CloneAs() - where TPixel2 : struct, IPixel => this.CloneAs(this.configuration); + where TPixel2 : struct, IPixel => this.CloneAs(this.Configuration); /// /// Returns a copy of the image frame in the given pixel format. diff --git a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs index 6f0bba5cf9..5c8e506ae1 100644 --- a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs @@ -4,8 +4,8 @@ using System; using System.Buffers; using System.Numerics; + using SixLabors.ImageSharp.Memory; -using SixLabors.Memory; namespace SixLabors.ImageSharp.PixelFormats { @@ -38,7 +38,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// 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. /// - protected abstract void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount); + protected abstract void BlendFunction( + Span destination, + ReadOnlySpan background, + ReadOnlySpan source, + float amount); /// /// Blend 2 rows together. @@ -50,12 +54,16 @@ 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. /// - protected abstract void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount); + protected abstract void BlendFunction( + Span destination, + ReadOnlySpan background, + ReadOnlySpan source, + ReadOnlySpan amount); /// /// Blends 2 rows together /// - /// memory manager to use internally + /// to use internally /// the destination span /// the background span /// the source span @@ -63,16 +71,21 @@ 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) + public void Blend( + Configuration configuration, + Span destination, + ReadOnlySpan background, + ReadOnlySpan source, + ReadOnlySpan amount) { - this.Blend(memoryManager, destination, background, source, amount); + this.Blend(configuration, destination, background, source, amount); } /// /// Blends 2 rows together /// /// the pixel format of the source span - /// memory manager to use internally + /// to use internally /// the destination span /// the background span /// the source span @@ -80,25 +93,40 @@ 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) + public void Blend( + Configuration configuration, + 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)) + using (IMemoryOwner buffer = + configuration.MemoryAllocator.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.ToScaledVector4(background.Slice(0, background.Length), backgroundSpan); - PixelOperations.Instance.ToScaledVector4(source.Slice(0, background.Length), sourceSpan); + PixelOperations.Instance.ToScaledVector4( + configuration, + background.Slice(0, background.Length), + backgroundSpan); + PixelOperations.Instance.ToScaledVector4( + configuration, + source.Slice(0, background.Length), + sourceSpan); this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); - PixelOperations.Instance.FromScaledVector4(destinationSpan.Slice(0, background.Length), destination); + PixelOperations.Instance.FromScaledVector4( + configuration, + destinationSpan.Slice(0, background.Length), + destination); } } @@ -106,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Blends 2 rows together /// /// the pixel format of the source span - /// memory manager to use internally + /// to use internally /// the destination span /// the background span /// the source span @@ -114,26 +142,41 @@ namespace SixLabors.ImageSharp.PixelFormats /// 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) + public void Blend( + Configuration configuration, + 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)) + using (IMemoryOwner buffer = + configuration.MemoryAllocator.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.ToScaledVector4(background.Slice(0, background.Length), backgroundSpan); - PixelOperations.Instance.ToScaledVector4(source.Slice(0, background.Length), sourceSpan); + PixelOperations.Instance.ToScaledVector4( + configuration, + background.Slice(0, background.Length), + backgroundSpan); + PixelOperations.Instance.ToScaledVector4( + configuration, + source.Slice(0, background.Length), + sourceSpan); this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); - PixelOperations.Instance.FromScaledVector4(destinationSpan.Slice(0, background.Length), destination); + PixelOperations.Instance.FromScaledVector4( + configuration, + destinationSpan.Slice(0, background.Length), + destination); } } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs index c25baa4512..0f5ddf3729 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs @@ -19,7 +19,10 @@ namespace SixLabors.ImageSharp.PixelFormats internal partial class PixelOperations : PixelOperations { /// - internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors) + internal override void ToVector4( + Configuration configuration, + ReadOnlySpan sourceColors, + Span destinationVectors) { Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); @@ -31,7 +34,10 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void FromVector4(ReadOnlySpan sourceVectors, Span destinationColors) + internal override void FromVector4( + Configuration configuration, + ReadOnlySpan sourceVectors, + Span destinationColors) { Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); @@ -43,17 +49,21 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors) + internal override void ToScaledVector4( + Configuration configuration, + ReadOnlySpan sourceColors, + Span destinationVectors) { - this.ToVector4(sourceColors, destinationVectors); + this.ToVector4(configuration, sourceColors, destinationVectors); } /// internal override void FromScaledVector4( + Configuration configuration, ReadOnlySpan sourceVectors, Span destinationColors) { - this.FromVector4(sourceVectors, destinationColors); + this.FromVector4(configuration, sourceVectors, destinationColors); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs index d1f3263659..cb12d944c7 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs @@ -19,6 +19,7 @@ namespace SixLabors.ImageSharp.PixelFormats { /// internal override void FromScaledVector4( + Configuration configuration, ReadOnlySpan sourceVectors, Span destinationColors) { @@ -29,12 +30,16 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToScaledVector4( + Configuration configuration, ReadOnlySpan sourceColors, Span destinationVectors) - => this.ToVector4(sourceColors, destinationVectors); + => this.ToVector4(configuration, sourceColors, destinationVectors); /// - internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors) + internal override void ToVector4( + Configuration configuration, + ReadOnlySpan sourceColors, + Span destinationVectors) { Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 510645c4e9..8f3ea6c11a 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -24,10 +24,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Bulk version of converting 'sourceVectors.Length' pixels into 'destinationColors'. /// + /// A to configure internal operations /// The to the source vectors. /// The to the destination colors. - internal virtual void FromVector4(ReadOnlySpan sourceVectors, Span destinationColors) + internal virtual void FromVector4( + Configuration configuration, + ReadOnlySpan sourceVectors, + Span destinationColors) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); @@ -44,10 +49,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Bulk version of converting 'sourceColors.Length' pixels into 'destinationVectors'. /// + /// A to configure internal operations /// The to the source colors. /// The to the destination vectors. - internal virtual void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors) + internal virtual void ToVector4( + Configuration configuration, + ReadOnlySpan sourceColors, + Span destinationVectors) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); @@ -64,10 +74,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Bulk version of converting 'sourceVectors.Length' pixels into 'destinationColors'. /// + /// A to configure internal operations /// The to the source vectors. /// The to the destination colors. - internal virtual void FromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors) + internal virtual void FromScaledVector4( + Configuration configuration, + ReadOnlySpan sourceVectors, + Span destinationColors) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); @@ -84,10 +99,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Bulk version of converting 'sourceColors.Length' pixels into 'destinationVectors'. /// + /// A to configure internal operations /// The to the source colors. /// The to the destination vectors. - internal virtual void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors) + internal virtual void ToScaledVector4( + Configuration configuration, + ReadOnlySpan sourceColors, + Span destinationVectors) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs index a26fe6bfd1..bd1419e4bb 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs @@ -75,14 +75,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan.Slice(0, length), vectorSpan); + PixelOperations.Instance.ToVector4(configuration, targetRowSpan.Slice(0, length), vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve2D(in matrixY, in matrixX, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.FromVector4(vectorSpan.Slice(0, length), targetRowSpan); + PixelOperations.Instance.FromVector4(configuration, vectorSpan.Slice(0, length), targetRowSpan); } }); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs index 98accb6061..05007c3706 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs @@ -93,14 +93,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan.Slice(0, length), vectorSpan); + PixelOperations.Instance.ToVector4(configuration, targetRowSpan.Slice(0, length), vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve(in matrix, sourcePixels, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.FromVector4(vectorSpan.Slice(0, length), targetRowSpan); + PixelOperations.Instance.FromVector4(configuration, vectorSpan.Slice(0, length), targetRowSpan); } }); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs index dcecf2b827..8ef64bdacc 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs @@ -59,14 +59,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan.Slice(0, length), vectorSpan); + PixelOperations.Instance.ToVector4(configuration, targetRowSpan.Slice(0, length), vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve(in matrix, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.FromVector4(vectorSpan.Slice(0, length), targetRowSpan); + PixelOperations.Instance.FromVector4(configuration, vectorSpan.Slice(0, length), targetRowSpan); } }); diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs index fd93801092..f01865ec05 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Numerics; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Dithering { @@ -21,7 +22,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// /// The vector representation of the image palette. /// - private readonly Vector4[] paletteVector; + private Vector4[] paletteVector; /// /// Initializes a new instance of the class. @@ -30,8 +31,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering protected PaletteDitherProcessorBase(TPixel[] palette) { this.Palette = palette ?? throw new ArgumentNullException(nameof(palette)); - this.paletteVector = new Vector4[this.Palette.Length]; - PixelOperations.Instance.ToScaledVector4(this.Palette, this.paletteVector); } /// @@ -40,7 +39,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering public TPixel[] Palette { get; } /// - /// Returns the two closest colors from the palette calcluated via Euclidean distance in the Rgba space. + /// Returns the two closest colors from the palette calculated via Euclidean distance in the Rgba space. /// /// The source color to match. /// The . @@ -90,5 +89,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering return pair; } + + protected override void BeforeFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + { + base.BeforeFrameApply(source, sourceRectangle, configuration); + + // Lazy init paletteVector: + if (this.paletteVector == null) + { + this.paletteVector = new Vector4[this.Palette.Length]; + PixelOperations.Instance.ToScaledVector4(configuration, this.Palette, this.paletteVector); + } + } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs index 4adddd1536..25787ff922 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs @@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays // 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, + source.Configuration, destination, colors.GetSpan(), destination, diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs index 93d6edff19..21f6be69f8 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs @@ -145,7 +145,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays Span destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); this.blender.Blend( - source.MemoryAllocator, + source.Configuration, destination, destination, rowColors.GetSpan(), diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs index 52dade4eff..a8fa1d65c1 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs @@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays Span destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); this.blender.Blend( - source.MemoryAllocator, + source.Configuration, destination, destination, rowColors.GetSpan(), diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs index bc0ed0eab1..a41127bfcb 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs @@ -17,6 +17,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public abstract class FrameQuantizerBase : IFrameQuantizer where TPixel : struct, IPixel { + private readonly Configuration configuration; + /// /// A lookup table for colors /// @@ -79,7 +81,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization // Collect the palette. Required before the second pass runs. TPixel[] palette = this.GetPalette(); this.paletteVector = new Vector4[palette.Length]; - PixelOperations.Instance.ToScaledVector4(palette, this.paletteVector); + PixelOperations.Instance.ToScaledVector4(image.Configuration, palette, this.paletteVector); var quantizedFrame = new QuantizedFrame(image.MemoryAllocator, width, height, palette); if (this.Dither) diff --git a/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs index 3da09cde09..f1490a6d2b 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs @@ -19,18 +19,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Creates the generic frame quantizer /// + /// The to configure internal operations. /// The pixel format. /// The - IFrameQuantizer CreateFrameQuantizer() + IFrameQuantizer CreateFrameQuantizer(Configuration configuration) where TPixel : struct, IPixel; /// /// Creates the generic frame quantizer /// /// The pixel format. + /// The to configure internal operations. /// The maximum number of colors to hold in the color palette. /// The - IFrameQuantizer CreateFrameQuantizer(int maxColors) + IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) where TPixel : struct, IPixel; } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs index 22bb5223f0..38962c7680 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs @@ -74,13 +74,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public int MaxColors { get; } + /// /// - public IFrameQuantizer CreateFrameQuantizer() + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration) where TPixel : struct, IPixel => new OctreeFrameQuantizer(this); /// - public IFrameQuantizer CreateFrameQuantizer(int maxColors) + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) where TPixel : struct, IPixel { maxColors = maxColors.Clamp(1, DefaultMaxColors); diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs index 625400413d..cab3af6de9 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs @@ -31,9 +31,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Initializes a new instance of the class. /// + /// The to configure internal operations. /// The palette quantizer. /// An array of all colors in the palette. - public PaletteFrameQuantizer(PaletteQuantizer quantizer, TPixel[] colors) + public PaletteFrameQuantizer(Configuration configuration, PaletteQuantizer quantizer, TPixel[] colors) : base(quantizer, true) { // TODO: Why is this value constrained? Gif has limitations but theoretically @@ -41,7 +42,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization Guard.MustBeBetweenOrEqualTo(colors.Length, 1, 256, nameof(colors)); this.palette = colors; this.paletteVector = new Vector4[this.palette.Length]; - PixelOperations.Instance.ToScaledVector4(this.palette, this.paletteVector); + PixelOperations.Instance.ToScaledVector4(configuration, this.palette, this.paletteVector); } /// diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs index 27ef05dfe9..361791253e 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs @@ -43,12 +43,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public IErrorDiffuser Diffuser { get; } /// - public virtual IFrameQuantizer CreateFrameQuantizer() + public virtual IFrameQuantizer CreateFrameQuantizer(Configuration configuration) where TPixel : struct, IPixel - => this.CreateFrameQuantizer(() => NamedColors.WebSafePalette); + => this.CreateFrameQuantizer(configuration, () => NamedColors.WebSafePalette); /// - public IFrameQuantizer CreateFrameQuantizer(int maxColors) + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) where TPixel : struct, IPixel { TPixel[] websafe = NamedColors.WebSafePalette; @@ -56,21 +56,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (max != websafe.Length) { - return this.CreateFrameQuantizer(() => NamedColors.WebSafePalette.AsSpan(0, max).ToArray()); + return this.CreateFrameQuantizer(configuration, () => NamedColors.WebSafePalette.AsSpan(0, max).ToArray()); } - return this.CreateFrameQuantizer(() => websafe); + return this.CreateFrameQuantizer(configuration, () => websafe); } /// /// Gets the palette to use to quantize the image. /// /// The pixel format. + /// The to configure internal operations /// The method to return the palette. /// The - public IFrameQuantizer CreateFrameQuantizer(Func paletteFunction) + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, Func paletteFunction) where TPixel : struct, IPixel - => new PaletteFrameQuantizer(this, paletteFunction.Invoke()); + => new PaletteFrameQuantizer(configuration, this, paletteFunction.Invoke()); private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null; } diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs index bd5a6e9ec7..8da89bf94a 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - IFrameQuantizer executor = this.Quantizer.CreateFrameQuantizer(); + IFrameQuantizer executor = this.Quantizer.CreateFrameQuantizer(configuration); using (QuantizedFrame quantized = executor.QuantizeFrame(source)) { int paletteCount = quantized.Palette.Length - 1; diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs index 5123e737d3..4cd09a14f4 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs @@ -73,13 +73,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public int MaxColors { get; } + /// /// - public IFrameQuantizer CreateFrameQuantizer() + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration) where TPixel : struct, IPixel => new WuFrameQuantizer(this); /// - public IFrameQuantizer CreateFrameQuantizer(int maxColors) + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) where TPixel : struct, IPixel { maxColors = maxColors.Clamp(1, DefaultMaxColors); diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 05c4464f18..4d4ed06ce1 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -257,7 +257,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Span sourceRow = source.GetPixelRowSpan(y); Span tempRowSpan = tempRowBuffer.Span; - PixelOperations.Instance.ToVector4(sourceRow, tempRowSpan); + PixelOperations.Instance.ToVector4(configuration, sourceRow, tempRowSpan); Vector4Utils.Premultiply(tempRowSpan); ref Vector4 firstPassBaseRef = ref firstPassPixelsTransposed.Span[y]; @@ -309,7 +309,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } Span targetRowSpan = destination.GetPixelRowSpan(y); - PixelOperations.Instance.FromVector4(tempRowSpan, targetRowSpan); + PixelOperations.Instance.FromVector4(configuration, tempRowSpan, targetRowSpan); } }); } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs index 1cd8c0196b..2b9573ed73 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs @@ -24,6 +24,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk protected IMemoryOwner destination; + protected Configuration Configuration => Configuration.Default; + [Params( 64, 2048 @@ -33,8 +35,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [GlobalSetup] public void Setup() { - this.destination = Configuration.Default.MemoryAllocator.Allocate(this.Count); - this.source = Configuration.Default.MemoryAllocator.Allocate(this.Count); + this.destination = this.Configuration.MemoryAllocator.Allocate(this.Count); + this.source = this.Configuration.MemoryAllocator.Allocate(this.Count); } [GlobalCleanup] @@ -59,13 +61,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Benchmark] public void PixelOperations_Base() { - new PixelOperations().FromVector4(this.source.GetSpan(), this.destination.GetSpan()); + new PixelOperations().FromVector4(this.Configuration, this.source.GetSpan(), this.destination.GetSpan()); } [Benchmark] public void PixelOperations_Specialized() { - PixelOperations.Instance.FromVector4(this.source.GetSpan(), this.destination.GetSpan()); + PixelOperations.Instance.FromVector4(this.Configuration, this.source.GetSpan(), this.destination.GetSpan()); } } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index e313953a6c..f0fee649af 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -10,10 +10,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Attributes.Jobs; -using BenchmarkDotNet.Configs; -using BenchmarkDotNet.Environments; -using BenchmarkDotNet.Jobs; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -27,20 +23,21 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk protected IMemoryOwner destination; + protected Configuration Configuration => Configuration.Default; + [Params( - 64, + 64, //256, //512, //1024, - 2048 - )] + 2048)] public int Count { get; set; } [GlobalSetup] public void Setup() { - this.source = Configuration.Default.MemoryAllocator.Allocate(this.Count); - this.destination = Configuration.Default.MemoryAllocator.Allocate(this.Count); + this.source = this.Configuration.MemoryAllocator.Allocate(this.Count); + this.destination = this.Configuration.MemoryAllocator.Allocate(this.Count); } [GlobalCleanup] @@ -65,13 +62,19 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Benchmark] public void PixelOperations_Base() { - new PixelOperations().ToVector4(this.source.GetSpan(), this.destination.GetSpan()); + new PixelOperations().ToVector4( + this.Configuration, + this.source.GetSpan(), + this.destination.GetSpan()); } [Benchmark] public void PixelOperations_Specialized() { - PixelOperations.Instance.ToVector4(this.source.GetSpan(), this.destination.GetSpan()); + PixelOperations.Instance.ToVector4( + this.Configuration, + this.source.GetSpan(), + this.destination.GetSpan()); } } diff --git a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs index 051646f90b..cdd56fa074 100644 --- a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs +++ b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs @@ -17,6 +17,8 @@ namespace SixLabors.ImageSharp.Benchmarks public class PorterDuffBulkVsPixel : BenchmarkBase { + private Configuration Configuration => Configuration.Default; + private void BulkVectorConvert( Span destination, Span background, @@ -35,15 +37,15 @@ namespace SixLabors.ImageSharp.Benchmarks Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - PixelOperations.Instance.ToVector4(background, backgroundSpan); - PixelOperations.Instance.ToVector4(source, sourceSpan); + PixelOperations.Instance.ToVector4(this.Configuration, background, backgroundSpan); + PixelOperations.Instance.ToVector4(this.Configuration, source, sourceSpan); for (int i = 0; i < destination.Length; i++) { destinationSpan[i] = PorterDuffFunctions.NormalSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); } - PixelOperations.Instance.FromVector4(destinationSpan, destination); + PixelOperations.Instance.FromVector4(this.Configuration, destinationSpan, destination); } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs index cfa421a82b..b3219115db 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { string imageFile = provider.SourceFileOrDescription; using (JpegDecoderCore decoder = JpegFixture.ParseJpegStream(imageFile)) - using (var pp = new JpegImagePostProcessor(Configuration.Default.MemoryAllocator, decoder)) + using (var pp = new JpegImagePostProcessor(Configuration.Default, decoder)) using (var imageFrame = new ImageFrame(Configuration.Default, decoder.ImageWidth, decoder.ImageHeight)) { pp.DoPostProcessorStep(imageFrame); @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { string imageFile = provider.SourceFileOrDescription; using (JpegDecoderCore decoder = JpegFixture.ParseJpegStream(imageFile)) - using (var pp = new JpegImagePostProcessor(Configuration.Default.MemoryAllocator, decoder)) + using (var pp = new JpegImagePostProcessor(Configuration.Default, decoder)) using (var image = new Image(decoder.ImageWidth, decoder.ImageHeight)) { pp.PostProcess(image.Frames.RootFrame); diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs index 3ea9bcad40..7de1cbb190 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders { new TestPixel(1,1,1,1), new TestPixel(0,0,0,.8f), .5f, new TestPixel(0.6f, 0.6f, 0.6f, 1) }, }; - private MemoryAllocator MemoryAllocator { get; } = Configuration.Default.MemoryAllocator; + private Configuration Configuration => Configuration.Default; [Theory] [MemberData(nameof(NormalBlendFunctionData))] @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.NormalSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.NormalSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.MultiplySrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.MultiplySrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.AddSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.AddSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -167,7 +167,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.SubtractSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.SubtractSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -206,7 +206,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.ScreenSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.ScreenSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -245,7 +245,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.DarkenSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.DarkenSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -284,7 +284,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.LightenSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.LightenSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -323,7 +323,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.OverlaySrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.OverlaySrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -362,7 +362,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.HardLightSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.HardLightSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 0082e6c0ec..8314bd9b4d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -269,7 +269,10 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { this.Measure( times, - () => PixelOperations.Instance.ToVector4(source.GetSpan(), dest.GetSpan())); + () => PixelOperations.Instance.ToVector4( + this.Configuration, + source.GetSpan(), + dest.GetSpan())); } } } @@ -333,6 +336,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public static TheoryData ArraySizesData => new TheoryData { 0, 1, 2, 7, 16, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 1111 }; + protected Configuration Configuration => Configuration.Default; + internal static PixelOperations Operations => PixelOperations.Instance; internal static TPixel[] CreateExpectedPixelData(Vector4[] source) @@ -367,7 +372,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromVector4(s, d.GetSpan()) + (s, d) => Operations.FromVector4(this.Configuration, s, d.GetSpan()) ); } @@ -381,7 +386,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromScaledVector4(s, d.GetSpan()) + (s, d) => Operations.FromScaledVector4(this.Configuration, s, d.GetSpan()) ); } @@ -417,7 +422,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToVector4(s, d.GetSpan()) + (s, d) => Operations.ToVector4(this.Configuration, s, d.GetSpan()) ); } @@ -431,7 +436,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToScaledVector4(s, d.GetSpan()) + (s, d) => Operations.ToScaledVector4(this.Configuration, s, d.GetSpan()) ); } diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index 719e9793a0..fa855aef77 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -10,6 +10,8 @@ namespace SixLabors.ImageSharp.Tests { public class QuantizedImageTests { + private Configuration Configuration => Configuration.Default; + [Fact] public void QuantizersDitherByDefault() { @@ -21,15 +23,17 @@ namespace SixLabors.ImageSharp.Tests Assert.NotNull(octree.Diffuser); Assert.NotNull(wu.Diffuser); - Assert.True(palette.CreateFrameQuantizer().Dither); - Assert.True(octree.CreateFrameQuantizer().Dither); - Assert.True(wu.CreateFrameQuantizer().Dither); + Assert.True(palette.CreateFrameQuantizer(this.Configuration).Dither); + Assert.True(octree.CreateFrameQuantizer(this.Configuration).Dither); + Assert.True(wu.CreateFrameQuantizer(this.Configuration).Dither); } [Theory] [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, true)] [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, false)] - public void PaletteQuantizerYieldsCorrectTransparentPixel(TestImageProvider provider, bool dither) + public void PaletteQuantizerYieldsCorrectTransparentPixel( + TestImageProvider provider, + bool dither) where TPixel : struct, IPixel { using (Image image = provider.GetImage()) @@ -40,7 +44,8 @@ namespace SixLabors.ImageSharp.Tests foreach (ImageFrame frame in image.Frames) { - QuantizedFrame quantized = quantizer.CreateFrameQuantizer().QuantizeFrame(frame); + QuantizedFrame quantized = + quantizer.CreateFrameQuantizer(this.Configuration).QuantizeFrame(frame); int index = this.GetTransparentIndex(quantized); Assert.Equal(index, quantized.GetPixelSpan()[0]); @@ -51,7 +56,9 @@ namespace SixLabors.ImageSharp.Tests [Theory] [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, true)] [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, false)] - public void OctreeQuantizerYieldsCorrectTransparentPixel(TestImageProvider provider, bool dither) + public void OctreeQuantizerYieldsCorrectTransparentPixel( + TestImageProvider provider, + bool dither) where TPixel : struct, IPixel { using (Image image = provider.GetImage()) @@ -62,7 +69,8 @@ namespace SixLabors.ImageSharp.Tests foreach (ImageFrame frame in image.Frames) { - QuantizedFrame quantized = quantizer.CreateFrameQuantizer().QuantizeFrame(frame); + QuantizedFrame quantized = + quantizer.CreateFrameQuantizer(this.Configuration).QuantizeFrame(frame); int index = this.GetTransparentIndex(quantized); Assert.Equal(index, quantized.GetPixelSpan()[0]); @@ -84,7 +92,8 @@ namespace SixLabors.ImageSharp.Tests foreach (ImageFrame frame in image.Frames) { - QuantizedFrame quantized = quantizer.CreateFrameQuantizer().QuantizeFrame(frame); + QuantizedFrame quantized = + quantizer.CreateFrameQuantizer(this.Configuration).QuantizeFrame(frame); int index = this.GetTransparentIndex(quantized); Assert.Equal(index, quantized.GetPixelSpan()[0]); diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index f055ce5480..29d39596b7 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -30,27 +30,29 @@ namespace SixLabors.ImageSharp.Tests { MemoryAllocator memoryAllocator = ctx.MemoryAllocator; - ctx.Apply(img => - { - using (Buffer2D temp = memoryAllocator.Allocate2D(img.Width, img.Height)) - { - Span tempSpan = temp.GetSpan(); - foreach (ImageFrame frame in img.Frames) + ctx.Apply( + img => { - Span pixelSpan = frame.GetPixelSpan(); + Configuration configuration = img.GetConfiguration(); + using (Buffer2D temp = memoryAllocator.Allocate2D(img.Width, img.Height)) + { + Span tempSpan = temp.GetSpan(); + foreach (ImageFrame frame in img.Frames) + { + Span pixelSpan = frame.GetPixelSpan(); - PixelOperations.Instance.ToScaledVector4(pixelSpan, tempSpan); + PixelOperations.Instance.ToScaledVector4(configuration, pixelSpan, tempSpan); - for (int i = 0; i < tempSpan.Length; i++) - { - ref Vector4 v = ref tempSpan[i]; - v.W = 1F; - } + for (int i = 0; i < tempSpan.Length; i++) + { + ref Vector4 v = ref tempSpan[i]; + v.W = 1F; + } - PixelOperations.Instance.FromScaledVector4(tempSpan, pixelSpan); - } - } - }); + PixelOperations.Instance.FromScaledVector4(configuration, tempSpan, pixelSpan); + } + } + }); } public static Image DebugSave( From 53ac430e7e48ce2a4043ada85fac44a75a089567 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 23 Oct 2018 01:49:24 +0200 Subject: [PATCH 212/381] Feed Configuration to all methods in PixelOperations --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 12 +- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 17 +- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 18 +- .../Encoder/YCbCrForwardConverter{TPixel}.cs | 6 +- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 2 + src/ImageSharp/Formats/Png/PngEncoderCore.cs | 46 +++-- .../Formats/Png/PngScanlineProcessor.cs | 8 +- src/ImageSharp/ImageFrame{TPixel}.cs | 4 +- .../PixelFormats/NamedColors{TPixel}.cs | 6 +- .../Argb32.PixelOperations.Generated.cs | 20 +- .../Bgr24.PixelOperations.Generated.cs | 20 +- .../Bgra32.PixelOperations.Generated.cs | 20 +- .../Gray16.PixelOperations.Generated.cs | 20 +- .../Gray8.PixelOperations.Generated.cs | 20 +- .../Rgb24.PixelOperations.Generated.cs | 20 +- .../Rgb48.PixelOperations.Generated.cs | 20 +- .../Rgba32.PixelOperations.Generated.cs | 20 +- .../Rgba64.PixelOperations.Generated.cs | 20 +- .../Generated/_Common.ttinclude | 6 +- .../PixelOperations{TPixel}.Generated.cs | 180 +++++++++++------- .../PixelOperations{TPixel}.Generated.tt | 20 +- .../PixelFormats/PixelOperations{TPixel}.cs | 2 + .../Quantization/WuFrameQuantizer{TPixel}.cs | 2 +- .../Color/Bulk/FromRgba32Bytes.cs | 11 +- .../ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs | 21 +- .../Color/Bulk/ToXyzw.cs | 21 +- .../PixelFormats/PixelOperationsTests.cs | 44 ++--- .../ImageComparison/ExactImageComparer.cs | 5 +- .../ImageComparison/TolerantImageComparer.cs | 5 +- .../ReferenceCodecs/MagickReferenceDecoder.cs | 12 +- .../ReferenceCodecs/SystemDrawingBridge.cs | 23 ++- 31 files changed, 405 insertions(+), 246 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 77cd322221..cea90cb45e 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -436,7 +436,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.stream.Read(row); int newY = Invert(y, height, inverted); Span pixelSpan = pixels.GetRowSpan(newY); - PixelOperations.Instance.FromBgr24Bytes(row.GetSpan(), pixelSpan, width); + PixelOperations.Instance.FromBgr24Bytes( + this.configuration, + row.GetSpan(), + pixelSpan, + width); } } } @@ -461,7 +465,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.stream.Read(row); int newY = Invert(y, height, inverted); Span pixelSpan = pixels.GetRowSpan(newY); - PixelOperations.Instance.FromBgra32Bytes(row.GetSpan(), pixelSpan, width); + PixelOperations.Instance.FromBgra32Bytes( + this.configuration, + row.GetSpan(), + pixelSpan, + width); } } } diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 186ff812f7..a67c581eb0 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -3,6 +3,8 @@ using System; using System.IO; + +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.MetaData; @@ -23,6 +25,8 @@ namespace SixLabors.ImageSharp.Formats.Bmp private readonly MemoryAllocator memoryAllocator; + private Configuration configuration; + private BmpBitsPerPixel? bitsPerPixel; /// @@ -48,6 +52,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); + this.configuration = image.GetConfiguration(); ImageMetaData metaData = image.MetaData; BmpMetaData bmpMetaData = metaData.GetFormatMetaData(BmpFormat.Instance); this.bitsPerPixel = this.bitsPerPixel ?? bmpMetaData.BitsPerPixel; @@ -163,7 +168,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp for (int y = pixels.Height - 1; y >= 0; y--) { Span pixelSpan = pixels.GetRowSpan(y); - PixelOperations.Instance.ToBgra32Bytes(pixelSpan, row.GetSpan(), pixelSpan.Length); + PixelOperations.Instance.ToBgra32Bytes( + this.configuration, + pixelSpan, + row.GetSpan(), + pixelSpan.Length); stream.Write(row.Array, 0, row.Length()); } } @@ -183,7 +192,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp for (int y = pixels.Height - 1; y >= 0; y--) { Span pixelSpan = pixels.GetRowSpan(y); - PixelOperations.Instance.ToBgr24Bytes(pixelSpan, row.GetSpan(), pixelSpan.Length); + PixelOperations.Instance.ToBgr24Bytes( + this.configuration, + pixelSpan, + row.GetSpan(), + pixelSpan.Length); stream.Write(row.Array, 0, row.Length()); } } diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 81adf52ddb..d7e2e40e29 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -27,6 +27,11 @@ namespace SixLabors.ImageSharp.Formats.Gif /// private readonly MemoryAllocator memoryAllocator; + /// + /// Configuration bound to the encoding operation. + /// + private Configuration configuration; + /// /// A reusable buffer used to reduce allocations. /// @@ -82,6 +87,8 @@ namespace SixLabors.ImageSharp.Formats.Gif Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); + this.configuration = image.GetConfiguration(); + ImageMetaData metaData = image.MetaData; this.gifMetaData = metaData.GetFormatMetaData(GifFormat.Instance); this.colorTableMode = this.colorTableMode ?? this.gifMetaData.ColorTableMode; @@ -220,7 +227,7 @@ namespace SixLabors.ImageSharp.Formats.Gif { Span rgbaSpan = rgbaBuffer.GetSpan(); ref Rgba32 paletteRef = ref MemoryMarshal.GetReference(rgbaSpan); - PixelOperations.Instance.ToRgba32(quantized.Palette, rgbaSpan); + PixelOperations.Instance.ToRgba32(this.configuration, quantized.Palette, rgbaSpan); for (int i = quantized.Palette.Length - 1; i >= 0; i--) { @@ -322,7 +329,8 @@ namespace SixLabors.ImageSharp.Formats.Gif /// The stream to write to. private void WriteComments(ImageMetaData metadata, Stream stream) { - if (!metadata.TryGetProperty(GifConstants.Comments, out ImageProperty property) || string.IsNullOrEmpty(property.Value)) + if (!metadata.TryGetProperty(GifConstants.Comments, out ImageProperty property) + || string.IsNullOrEmpty(property.Value)) { return; } @@ -420,7 +428,11 @@ namespace SixLabors.ImageSharp.Formats.Gif using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength)) { - PixelOperations.Instance.ToRgb24Bytes(image.Palette.AsSpan(), colorTable.GetSpan(), pixelCount); + PixelOperations.Instance.ToRgb24Bytes( + this.configuration, + image.Palette.AsSpan(), + colorTable.GetSpan(), + pixelCount); stream.Write(colorTable.Array, 0, colorTableLength); } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs index b2a8fccf4a..d775425c5c 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs @@ -53,12 +53,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder /// /// Converts a 8x8 image area inside 'pixels' at position (x,y) placing the result members of the structure (, , ) /// - public void Convert(IPixelSource pixels, int x, int y) + public void Convert(ImageFrame frame, int x, int y) { - this.pixelBlock.LoadAndStretchEdges(pixels, x, y); + this.pixelBlock.LoadAndStretchEdges(frame, x, y); Span rgbSpan = this.rgbBlock.AsSpanUnsafe(); - PixelOperations.Instance.ToRgb24(this.pixelBlock.AsSpanUnsafe(), rgbSpan); + PixelOperations.Instance.ToRgb24(frame.Configuration, this.pixelBlock.AsSpanUnsafe(), rgbSpan); ref float yBlockStart = ref Unsafe.As(ref this.Y); ref float cbBlockStart = ref Unsafe.As(ref this.Cb); diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index d66ac6c0d2..11c4d831b0 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -702,6 +702,7 @@ namespace SixLabors.ImageSharp.Formats.Png case PngColorType.Rgb: PngScanlineProcessor.ProcessRgbScanline( + this.configuration, this.header, scanlineSpan, rowSpan, @@ -715,6 +716,7 @@ namespace SixLabors.ImageSharp.Formats.Png case PngColorType.RgbWithAlpha: PngScanlineProcessor.ProcessRgbaScanline( + this.configuration, this.header, scanlineSpan, rowSpan, diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 71945d1302..7ae716aa05 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -43,6 +43,11 @@ namespace SixLabors.ImageSharp.Formats.Png /// private readonly MemoryAllocator memoryAllocator; + /// + /// The configuration instance for the decoding operation + /// + private Configuration configuration; + /// /// The maximum block size, defaults at 64k for uncompressed blocks. /// @@ -201,6 +206,7 @@ namespace SixLabors.ImageSharp.Formats.Png Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); + this.configuration = image.GetConfiguration(); this.width = image.Width; this.height = image.Height; @@ -328,7 +334,7 @@ namespace SixLabors.ImageSharp.Formats.Png { Span luminanceSpan = luminanceBuffer.GetSpan(); ref Gray16 luminanceRef = ref MemoryMarshal.GetReference(luminanceSpan); - PixelOperations.Instance.ToGray16(rowSpan, luminanceSpan); + PixelOperations.Instance.ToGray16(this.configuration, rowSpan, luminanceSpan); // Can't map directly to byte array as it's big endian. for (int x = 0, o = 0; x < luminanceSpan.Length; x++, o += 2) @@ -343,19 +349,28 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.bitDepth == 8) { // 8 bit grayscale - PixelOperations.Instance.ToGray8Bytes(rowSpan, rawScanlineSpan, rowSpan.Length); + PixelOperations.Instance.ToGray8Bytes( + this.configuration, + rowSpan, + rawScanlineSpan, + rowSpan.Length); } else { // 1, 2, and 4 bit grayscale - using (IManagedByteBuffer temp = this.memoryAllocator.AllocateManagedByteBuffer(rowSpan.Length, AllocationOptions.Clean)) + using (IManagedByteBuffer temp = this.memoryAllocator.AllocateManagedByteBuffer( + rowSpan.Length, + AllocationOptions.Clean)) { int scaleFactor = 255 / (ImageMaths.GetColorCountForBitDepth(this.bitDepth) - 1); Span tempSpan = temp.GetSpan(); - ref byte tempSpanRef = ref MemoryMarshal.GetReference(tempSpan); // We need to first create an array of luminance bytes then scale them down to the correct bit depth. - PixelOperations.Instance.ToGray8Bytes(rowSpan, tempSpan, rowSpan.Length); + PixelOperations.Instance.ToGray8Bytes( + this.configuration, + rowSpan, + tempSpan, + rowSpan.Length); this.ScaleDownFrom8BitArray(tempSpan, rawScanlineSpan, this.bitDepth, scaleFactor); } } @@ -371,7 +386,7 @@ namespace SixLabors.ImageSharp.Formats.Png { Span rgbaSpan = rgbaBuffer.GetSpan(); ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan); - PixelOperations.Instance.ToRgba64(rowSpan, rgbaSpan); + PixelOperations.Instance.ToRgba64(this.configuration, rowSpan, rgbaSpan); // Can't map directly to byte array as it's big endian. for (int x = 0, o = 0; x < rgbaSpan.Length; x++, o += 4) @@ -391,7 +406,8 @@ namespace SixLabors.ImageSharp.Formats.Png for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 2) { Unsafe.Add(ref rowSpanRef, x).ToRgba32(ref rgba); - Unsafe.Add(ref rawScanlineSpanRef, o) = ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); + Unsafe.Add(ref rawScanlineSpanRef, o) = + ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); Unsafe.Add(ref rawScanlineSpanRef, o + 1) = rgba.A; } } @@ -413,14 +429,22 @@ namespace SixLabors.ImageSharp.Formats.Png case 4: { // 8 bit Rgba - PixelOperations.Instance.ToRgba32Bytes(rowSpan, rawScanlineSpan, this.width); + PixelOperations.Instance.ToRgba32Bytes( + this.configuration, + rowSpan, + rawScanlineSpan, + this.width); break; } case 3: { // 8 bit Rgb - PixelOperations.Instance.ToRgb24Bytes(rowSpan, rawScanlineSpan, this.width); + PixelOperations.Instance.ToRgb24Bytes( + this.configuration, + rowSpan, + rawScanlineSpan, + this.width); break; } @@ -431,7 +455,7 @@ namespace SixLabors.ImageSharp.Formats.Png { Span rgbaSpan = rgbaBuffer.GetSpan(); ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan); - PixelOperations.Instance.ToRgba64(rowSpan, rgbaSpan); + PixelOperations.Instance.ToRgba64(this.configuration, rowSpan, rgbaSpan); // Can't map directly to byte array as it's big endian. for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 8) @@ -454,7 +478,7 @@ namespace SixLabors.ImageSharp.Formats.Png { Span rgbSpan = rgbBuffer.GetSpan(); ref Rgb48 rgbRef = ref MemoryMarshal.GetReference(rgbSpan); - PixelOperations.Instance.ToRgb48(rowSpan, rgbSpan); + PixelOperations.Instance.ToRgb48(this.configuration, rowSpan, rgbSpan); // Can't map directly to byte array as it's big endian. for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 6) diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index e4a2562e65..3fe590ee24 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Png { /// /// Provides methods to allow the decoding of raw scanlines to image rows of different pixel formats. + /// TODO: We should make this a stateful class or struct to reduce the number of arguments on methods (most are invariant). /// internal static class PngScanlineProcessor { @@ -346,6 +347,7 @@ namespace SixLabors.ImageSharp.Formats.Png } public static void ProcessRgbScanline( + Configuration configuration, in PngHeader header, ReadOnlySpan scanlineSpan, Span rowSpan, @@ -357,7 +359,6 @@ namespace SixLabors.ImageSharp.Formats.Png where TPixel : struct, IPixel { TPixel pixel = default; - ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); if (!hasTrans) @@ -377,7 +378,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - PixelOperations.Instance.FromRgb24Bytes(scanlineSpan, rowSpan, header.Width); + PixelOperations.Instance.FromRgb24Bytes(configuration, scanlineSpan, rowSpan, header.Width); } return; @@ -500,6 +501,7 @@ namespace SixLabors.ImageSharp.Formats.Png } public static void ProcessRgbaScanline( + Configuration configuration, in PngHeader header, ReadOnlySpan scanlineSpan, Span rowSpan, @@ -526,7 +528,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - PixelOperations.Instance.FromRgba32Bytes(scanlineSpan, rowSpan, header.Width); + PixelOperations.Instance.FromRgba32Bytes(configuration, scanlineSpan, rowSpan, header.Width); } } diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index bb95bb7b6d..f69ae37574 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -252,7 +252,7 @@ namespace SixLabors.ImageSharp } /// - public override string ToString() => $"ImageFrame<{typeof(TPixel).Name}>: {this.Width}x{this.Height}"; + public override string ToString() => $"ImageFrame<{typeof(TPixel).Name}>({this.Width}x{this.Height})"; /// /// Clones the current instance. @@ -300,7 +300,7 @@ namespace SixLabors.ImageSharp { Span sourceRow = this.GetPixelRowSpan(y); Span targetRow = target.GetPixelRowSpan(y); - PixelOperations.Instance.To(sourceRow, targetRow); + PixelOperations.Instance.To(configuration, sourceRow, targetRow); } }); diff --git a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs index 1923faa1fc..08530c2bb5 100644 --- a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs @@ -739,7 +739,11 @@ namespace SixLabors.ImageSharp.PixelFormats var safe = new TPixel[constants.Length + 1]; Span constantsBytes = MemoryMarshal.Cast(constants.AsSpan()); - PixelOperations.Instance.FromRgba32Bytes(constantsBytes, safe, constants.Length); + PixelOperations.Instance.FromRgba32Bytes( + Configuration.Default, + constantsBytes, + safe, + constants.Length); return safe; } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs index 26e85e043d..09f10716e2 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromArgb32(ReadOnlySpan source, Span destPixels) + internal override void FromArgb32(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs index 080a25429b..f8c61e4fac 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromBgr24(ReadOnlySpan source, Span destPixels) + internal override void FromBgr24(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs index 6a1bb6cdc3..9bddd18e9c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromBgra32(ReadOnlySpan source, Span destPixels) + internal override void FromBgra32(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs index cbb9df4459..31c5755345 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromGray16(ReadOnlySpan source, Span destPixels) + internal override void FromGray16(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs index b88f18e8de..14a2c858cf 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromGray8(ReadOnlySpan source, Span destPixels) + internal override void FromGray8(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs index 49c56f4fa2..f8b80020ec 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromRgb24(ReadOnlySpan source, Span destPixels) + internal override void FromRgb24(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs index cda6dbf72c..5741b10706 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromRgb48(ReadOnlySpan source, Span destPixels) + internal override void FromRgb48(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs index ab264f8701..9f7b624c07 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromRgba32(ReadOnlySpan source, Span destPixels) + internal override void FromRgba32(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs index 4bc6b101ae..411178b825 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromRgba64(ReadOnlySpan source, Span destPixels) + internal override void FromRgba64(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude index 176075a40f..bc23edb015 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude @@ -19,7 +19,7 @@ using System.Runtime.InteropServices; #> /// - internal override void From<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destPixels) + internal override void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -27,7 +27,7 @@ using System.Runtime.InteropServices; } /// - internal override void To<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<<#=pixelType#>> destPixels) + internal override void To<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<<#=pixelType#>> destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -42,7 +42,7 @@ using System.Runtime.InteropServices; #> /// - internal override void To<#=toPixelType#>(ReadOnlySpan<<#=fromPixelType#>> sourcePixels, Span<<#=toPixelType#>> destPixels) + internal override void To<#=toPixelType#>(Configuration configuration, ReadOnlySpan<<#=fromPixelType#>> sourcePixels, Span<<#=toPixelType#>> destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs index 07ecf87569..207a8767d6 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs @@ -13,9 +13,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromArgb32(ReadOnlySpan source, Span destPixels) + internal virtual void FromArgb32(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -32,24 +33,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromArgb32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromArgb32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromArgb32(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromArgb32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -66,24 +69,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToArgb32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToArgb32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToArgb32(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToArgb32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromBgr24(ReadOnlySpan source, Span destPixels) + internal virtual void FromBgr24(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -100,24 +105,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromBgr24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromBgr24Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromBgr24(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromBgr24(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -134,24 +141,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToBgr24Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToBgr24Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToBgr24(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToBgr24(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromBgra32(ReadOnlySpan source, Span destPixels) + internal virtual void FromBgra32(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -168,24 +177,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromBgra32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromBgra32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromBgra32(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromBgra32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -202,24 +213,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToBgra32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToBgra32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToBgra32(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToBgra32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromGray8(ReadOnlySpan source, Span destPixels) + internal virtual void FromGray8(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -236,24 +249,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromGray8Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromGray8Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromGray8(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromGray8(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -270,24 +285,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToGray8Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToGray8Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToGray8(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToGray8(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromGray16(ReadOnlySpan source, Span destPixels) + internal virtual void FromGray16(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -304,24 +321,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromGray16Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromGray16Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromGray16(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromGray16(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -338,24 +357,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToGray16Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToGray16Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToGray16(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToGray16(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromRgb24(ReadOnlySpan source, Span destPixels) + internal virtual void FromRgb24(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -372,24 +393,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromRgb24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromRgb24Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromRgb24(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromRgb24(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -406,24 +429,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgb24Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToRgb24Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgb24(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToRgb24(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromRgba32(ReadOnlySpan source, Span destPixels) + internal virtual void FromRgba32(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -440,24 +465,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromRgba32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromRgba32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromRgba32(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromRgba32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -474,24 +501,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgba32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToRgba32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgba32(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToRgba32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromRgb48(ReadOnlySpan source, Span destPixels) + internal virtual void FromRgb48(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -508,24 +537,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromRgb48Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromRgb48Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromRgb48(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromRgb48(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -542,24 +573,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgb48Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToRgb48Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgb48(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToRgb48(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromRgba64(ReadOnlySpan source, Span destPixels) + internal virtual void FromRgba64(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -576,24 +609,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromRgba64Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromRgba64Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromRgba64(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromRgba64(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -610,16 +645,17 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgba64Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToRgba64Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgba64(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToRgba64(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt index ef73378a24..8579423b34 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt @@ -18,9 +18,10 @@ /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void From<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels) + internal virtual void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -37,16 +38,17 @@ } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void From<#=pixelType#>Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void From<#=pixelType#>Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.From<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes).Slice(0, count), destPixels); + this.From<#=pixelType#>(configuration, MemoryMarshal.Cast>(sourceBytes).Slice(0, count), destPixels); } <# @@ -58,9 +60,10 @@ /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels) + internal virtual void To<#=pixelType#>(Configuration configuration, ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -77,16 +80,17 @@ } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void To<#=pixelType#>Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void To<#=pixelType#>Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.To<#=pixelType#>(sourcePixels.Slice(0, count), MemoryMarshal.Cast>(destBytes)); + this.To<#=pixelType#>(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast>(destBytes)); } <# } diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 8f3ea6c11a..ea03af683d 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -125,9 +125,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// Converts 'sourceColors.Length' pixels from 'sourceColors' into 'destinationColors'. /// /// The destination pixel type. + /// A to configure internal operations /// The to the source colors. /// The to the destination colors. internal virtual void To( + Configuration configuration, ReadOnlySpan sourceColors, Span destinationColors) where TDestinationPixel : struct, IPixel diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 98a5d5eb51..43d22597df 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -448,7 +448,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { Span row = source.GetPixelRowSpan(y); Span rgbaSpan = rgbaBuffer.GetSpan(); - PixelOperations.Instance.ToRgba32(row, rgbaSpan); + PixelOperations.Instance.ToRgba32(source.Configuration, row, rgbaSpan); ref Rgba32 scanBaseRef = ref MemoryMarshal.GetReference(rgbaSpan); // And loop through each column diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs index f3245ebaf5..32565c23dc 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs @@ -20,14 +20,17 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk private IMemoryOwner source; + private Configuration configuration; + [Params(16, 128, 1024)] public int Count { get; set; } [GlobalSetup] public void Setup() { - this.destination = Configuration.Default.MemoryAllocator.Allocate(this.Count); - this.source = Configuration.Default.MemoryAllocator.Allocate(this.Count * 4); + this.configuration = Configuration.Default; + this.destination = this.configuration.MemoryAllocator.Allocate(this.Count); + this.source = this.configuration.MemoryAllocator.Allocate(this.Count * 4); } [GlobalCleanup] @@ -55,13 +58,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Benchmark] public void CommonBulk() { - new PixelOperations().FromRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + new PixelOperations().FromRgba32Bytes(this.configuration, this.source.GetSpan(), this.destination.GetSpan(), this.Count); } [Benchmark] public void OptimizedBulk() { - PixelOperations.Instance.FromRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + PixelOperations.Instance.FromRgba32Bytes(this.configuration, this.source.GetSpan(), this.destination.GetSpan(), this.Count); } } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs index f96023f000..912c3e4b2e 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs @@ -17,14 +17,17 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk private IMemoryOwner destination; + private Configuration configuration; + [Params(16, 128, 1024)] public int Count { get; set; } [GlobalSetup] public void Setup() { - this.source = Configuration.Default.MemoryAllocator.Allocate(this.Count); - this.destination = Configuration.Default.MemoryAllocator.Allocate(this.Count * 3); + this.configuration = Configuration.Default; + this.source = this.configuration.MemoryAllocator.Allocate(this.Count); + this.destination = this.configuration.MemoryAllocator.Allocate(this.Count * 3); } [GlobalCleanup] @@ -35,10 +38,20 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark(Baseline = true)] - public void CommonBulk() => new PixelOperations().ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + public void CommonBulk() => + new PixelOperations().ToRgb24Bytes( + this.configuration, + this.source.GetSpan(), + this.destination.GetSpan(), + this.Count); [Benchmark] - public void OptimizedBulk() => PixelOperations.Instance.ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + public void OptimizedBulk() => + PixelOperations.Instance.ToRgb24Bytes( + this.configuration, + this.source.GetSpan(), + this.destination.GetSpan(), + this.Count); } public class ToXyz_Rgba32 : ToXyz diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs index 0cf7087d4c..37694f64cd 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs @@ -19,14 +19,17 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk private IMemoryOwner destination; + private Configuration configuration; + [Params(16, 128, 1024)] public int Count { get; set; } [GlobalSetup] public void Setup() { - this.source = Configuration.Default.MemoryAllocator.Allocate(this.Count); - this.destination = Configuration.Default.MemoryAllocator.Allocate(this.Count * 4); + this.configuration = Configuration.Default; + this.source = this.configuration.MemoryAllocator.Allocate(this.Count); + this.destination = this.configuration.MemoryAllocator.Allocate(this.Count * 4); } [GlobalCleanup] @@ -56,10 +59,20 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark] - public void CommonBulk() => new PixelOperations().ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + public void CommonBulk() => + new PixelOperations().ToRgba32Bytes( + this.configuration, + this.source.GetSpan(), + this.destination.GetSpan(), + this.Count); [Benchmark] - public void OptimizedBulk() => PixelOperations.Instance.ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + public void OptimizedBulk() => + PixelOperations.Instance.ToRgba32Bytes( + this.configuration, + this.source.GetSpan(), + this.destination.GetSpan(), + this.Count); } public class ToXyzw_Rgba32 : ToXyzw diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 8314bd9b4d..e66ca9a714 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromGray8Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromGray8Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToGray8Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToGray8Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -123,7 +123,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromGray16Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromGray16Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToGray16Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToGray16Bytes(this.Configuration, s, d.GetSpan(), count) ); } } @@ -177,7 +177,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromGray8Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromGray8Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -198,7 +198,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToGray8Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToGray8Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -219,7 +219,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromGray16Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromGray16Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -243,7 +243,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToGray16Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToGray16Bytes(this.Configuration, s, d.GetSpan(), count) ); } } @@ -457,7 +457,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromArgb32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromArgb32Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -483,7 +483,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToArgb32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToArgb32Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -504,7 +504,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromBgr24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromBgr24Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -528,7 +528,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToBgr24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToBgr24Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -549,7 +549,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromBgra32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromBgra32Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -574,7 +574,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToBgra32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToBgra32Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -595,7 +595,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromRgb24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgb24Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -619,7 +619,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToRgb24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgb24Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -640,7 +640,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromRgba32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgba32Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -665,7 +665,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToRgba32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgba32Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -686,7 +686,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromRgb48Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgb48Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -714,7 +714,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToRgb48Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgb48Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -735,7 +735,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromRgba64Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgba64Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -765,7 +765,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToRgba64Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgba64Bytes(this.Configuration, s, d.GetSpan(), count) ); } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs index 886e02c139..462782ba5e 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs @@ -28,14 +28,15 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison var bBuffer = new Rgba64[width]; var differences = new List(); + Configuration configuration = expected.Configuration; for (int y = 0; y < actual.Height; y++) { Span aSpan = expected.GetPixelRowSpan(y); Span bSpan = actual.GetPixelRowSpan(y); - PixelOperations.Instance.ToRgba64(aSpan, aBuffer); - PixelOperations.Instance.ToRgba64(bSpan, bBuffer); + PixelOperations.Instance.ToRgba64(configuration, aSpan, aBuffer); + PixelOperations.Instance.ToRgba64(configuration, bSpan, bBuffer); for (int x = 0; x < width; x++) { diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs index 9563edbb58..be12f56211 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs @@ -74,14 +74,15 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison float totalDifference = 0F; var differences = new List(); + Configuration configuration = expected.Configuration; for (int y = 0; y < actual.Height; y++) { Span aSpan = expected.GetPixelRowSpan(y); Span bSpan = actual.GetPixelRowSpan(y); - PixelOperations.Instance.ToRgba64(aSpan, aBuffer); - PixelOperations.Instance.ToRgba64(bSpan, bBuffer); + PixelOperations.Instance.ToRgba64(configuration, aSpan, aBuffer); + PixelOperations.Instance.ToRgba64(configuration, bSpan, bBuffer); for (int x = 0; x < width; x++) { diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs index 2409ff9add..3dd330e4d3 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs @@ -31,14 +31,22 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs { byte[] data = pixels.ToByteArray(PixelMapping.RGBA); - PixelOperations.Instance.FromRgba32Bytes(data, resultPixels, resultPixels.Length); + PixelOperations.Instance.FromRgba32Bytes( + configuration, + data, + resultPixels, + resultPixels.Length); } else if (magickImage.Depth == 16) { ushort[] data = pixels.ToShortArray(PixelMapping.RGBA); Span bytes = MemoryMarshal.Cast(data.AsSpan()); - PixelOperations.Instance.FromRgba64Bytes(bytes, resultPixels, resultPixels.Length); + PixelOperations.Instance.FromRgba64Bytes( + configuration, + bytes, + resultPixels, + resultPixels.Length); } else { diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs index e96825db1c..7e87c23db5 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs @@ -33,7 +33,9 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs if (bmp.PixelFormat != PixelFormat.Format32bppArgb) { - throw new ArgumentException($"{nameof(From32bppArgbSystemDrawingBitmap)} : pixel format should be {PixelFormat.Format32bppArgb}!", nameof(bmp)); + throw new ArgumentException( + $"{nameof(From32bppArgbSystemDrawingBitmap)} : pixel format should be {PixelFormat.Format32bppArgb}!", + nameof(bmp)); } BitmapData data = bmp.LockBits(fullRect, ImageLockMode.ReadWrite, bmp.PixelFormat); @@ -43,6 +45,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs long destRowByteCount = w * sizeof(Bgra32); var image = new Image(w, h); + Configuration configuration = image.GetConfiguration(); using (IMemoryOwner workBuffer = Configuration.Default.MemoryAllocator.Allocate(w)) { @@ -55,7 +58,10 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); - PixelOperations.Instance.FromBgra32(workBuffer.GetSpan().Slice(0, w), row); + PixelOperations.Instance.FromBgra32( + configuration, + workBuffer.GetSpan().Slice(0, w), + row); } } } @@ -79,7 +85,9 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs if (bmp.PixelFormat != PixelFormat.Format24bppRgb) { - throw new ArgumentException($"{nameof(From24bppRgbSystemDrawingBitmap)}: pixel format should be {PixelFormat.Format24bppRgb}!", nameof(bmp)); + throw new ArgumentException( + $"{nameof(From24bppRgbSystemDrawingBitmap)}: pixel format should be {PixelFormat.Format24bppRgb}!", + nameof(bmp)); } BitmapData data = bmp.LockBits(fullRect, ImageLockMode.ReadWrite, bmp.PixelFormat); @@ -89,6 +97,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs long destRowByteCount = w * sizeof(Bgr24); var image = new Image(w, h); + Configuration configuration = image.GetConfiguration(); using (IMemoryOwner workBuffer = Configuration.Default.MemoryAllocator.Allocate(w)) { @@ -101,7 +110,10 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); - PixelOperations.Instance.FromBgr24(workBuffer.GetSpan().Slice(0, w), row); + PixelOperations.Instance.FromBgr24( + configuration, + workBuffer.GetSpan().Slice(0, w), + row); } } } @@ -112,6 +124,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs internal static unsafe Bitmap To32bppArgbSystemDrawingBitmap(Image image) where TPixel : struct, IPixel { + Configuration configuration = image.GetConfiguration(); int w = image.Width; int h = image.Height; @@ -130,7 +143,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs for (int y = 0; y < h; y++) { Span row = image.Frames.RootFrame.GetPixelRowSpan(y); - PixelOperations.Instance.ToBgra32(row, workBuffer.GetSpan()); + PixelOperations.Instance.ToBgra32(configuration, row, workBuffer.GetSpan()); byte* destPtr = destPtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); From e408b5ca91e22e40c8a88b3aaf0a0e98c79ea067 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 23 Oct 2018 11:32:22 +0200 Subject: [PATCH 213/381] revert addition of unnecessary `[DebuggerStepThrough]` --- src/ImageSharp/Common/Helpers/Guard.cs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs index cd53e3d69a..d8cf69a52e 100644 --- a/src/ImageSharp/Common/Helpers/Guard.cs +++ b/src/ImageSharp/Common/Helpers/Guard.cs @@ -21,7 +21,6 @@ namespace SixLabors.ImageSharp /// The name of the parameter that is to be checked. /// is null [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void NotNull(T value, string parameterName) where T : class { @@ -39,7 +38,6 @@ namespace SixLabors.ImageSharp /// is null. /// is empty or contains only blanks. [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void NotNullOrWhiteSpace(string value, string parameterName) { if (value is null) @@ -62,7 +60,6 @@ namespace SixLabors.ImageSharp /// is null. /// is empty. [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void NotNullOrEmpty(ICollection value, string parameterName) { if (value is null) @@ -87,7 +84,6 @@ namespace SixLabors.ImageSharp /// is greater than the maximum value. /// [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void MustBeLessThan(TValue value, TValue max, string parameterName) where TValue : IComparable { @@ -109,7 +105,6 @@ namespace SixLabors.ImageSharp /// is greater than the maximum value. /// [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void MustBeLessThanOrEqualTo(TValue value, TValue max, string parameterName) where TValue : IComparable { @@ -131,7 +126,6 @@ namespace SixLabors.ImageSharp /// is less than the minimum value. /// [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void MustBeGreaterThan(TValue value, TValue min, string parameterName) where TValue : IComparable { @@ -155,7 +149,6 @@ namespace SixLabors.ImageSharp /// is less than the minimum value. /// [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void MustBeGreaterThanOrEqualTo(TValue value, TValue min, string parameterName) where TValue : IComparable { @@ -178,7 +171,6 @@ namespace SixLabors.ImageSharp /// is less than the minimum value of greater than the maximum value. /// [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void MustBeBetweenOrEqualTo(TValue value, TValue min, TValue max, string parameterName) where TValue : IComparable { @@ -199,7 +191,6 @@ namespace SixLabors.ImageSharp /// is false /// [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void IsTrue(bool target, string parameterName, string message) { if (!target) @@ -219,7 +210,6 @@ namespace SixLabors.ImageSharp /// is true /// [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void IsFalse(bool target, string parameterName, string message) { if (target) @@ -239,7 +229,6 @@ namespace SixLabors.ImageSharp /// has less than items /// [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void MustBeSizedAtLeast(ReadOnlySpan source, int minLength, string parameterName) { if (source.Length < minLength) @@ -257,7 +246,6 @@ namespace SixLabors.ImageSharp /// The destination span /// The name of the argument for 'destination' [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void DestinationShouldNotBeTooShort( ReadOnlySpan source, Span destination, @@ -280,7 +268,6 @@ namespace SixLabors.ImageSharp /// has less than items /// [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void MustBeSizedAtLeast(Span source, int minLength, string parameterName) { if (source.Length < minLength) From 8dce0c740ce9660bd41b039a5023bbe204cdbf05 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 23 Oct 2018 11:06:32 +0200 Subject: [PATCH 214/381] bitwise conversion + benchmarks WIP --- .../Decoder/JpegImagePostProcessor.cs | 2 +- src/ImageSharp/PixelFormats/PixelConverter.cs | 47 ++++++ .../FrameQuantizerBase{TPixel}.cs | 2 - .../PixelConversion_ConvertFromRgba32.cs | 144 +++++++++++++---- .../General/PixelConversion/TestArgb.cs | 62 ++++---- .../General/PixelConversion/TestRgba.cs | 14 +- .../PixelFormats/PixelConverterTests.cs | 150 ++++++++++++++++++ .../PixelFormats/Rgba32Tests.cs | 1 + 8 files changed, 347 insertions(+), 75 deletions(-) create mode 100644 src/ImageSharp/PixelFormats/PixelConverter.cs create mode 100644 tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs index 1a6da2b2b0..7ce86b4c9b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs @@ -162,7 +162,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder this.colorConverter.ConvertToRgba(values, this.rgbaBuffer.GetSpan()); Span destRow = destination.GetPixelRowSpan(yy); - + // TODO: Investigate if slicing is actually necessary PixelOperations.Instance.FromVector4(this.configuration, this.rgbaBuffer.GetSpan().Slice(0, destRow.Length), destRow); } diff --git a/src/ImageSharp/PixelFormats/PixelConverter.cs b/src/ImageSharp/PixelFormats/PixelConverter.cs new file mode 100644 index 0000000000..3686092cd2 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelConverter.cs @@ -0,0 +1,47 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Contains optimized implementations for conversion between pixel formats. + /// + /// + /// Implementations are based on ideas in: + /// https://github.com/dotnet/coreclr/blob/master/src/System.Private.CoreLib/shared/System/Buffers/Binary/Reader.cs#L84 + /// The JIT should be able to detect and optimize ROL and ROR patterns. + /// + internal static class PixelConverter + { + public static class Rgba32 + { + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToArgb32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // ROL(8, packedRgba): + return (packedRgba << 8) | (packedRgba >> 24); + } + } + + public static class Argb32 + { + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToRgba32(uint packedArgb) + { + // packedArgb = [bb gg rr aa] + // ROR(8, packedArgb): + return (packedArgb >> 8) | (packedArgb << 24); + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs index a41127bfcb..a8c6c5d7e0 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs @@ -17,8 +17,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public abstract class FrameQuantizerBase : IFrameQuantizer where TPixel : struct, IPixel { - private readonly Configuration configuration; - /// /// A lookup table for colors /// diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs index 6a96c8576e..1be8347c3d 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs @@ -1,6 +1,8 @@ // ReSharper disable InconsistentNaming +using System; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; @@ -8,14 +10,14 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion { - public class PixelConversion_ConvertFromRgba32 + public abstract class PixelConversion_ConvertFromRgba32 { - struct ConversionRunner + internal struct ConversionRunner where T : struct, ITestPixel { - private T[] dest; + public readonly T[] dest; - private Rgba32[] source; + public readonly Rgba32[] source; public ConversionRunner(int count) { @@ -67,72 +69,146 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion } } - private ConversionRunner compatibleMemLayoutRunner; + internal ConversionRunner compatibleMemLayoutRunner; - private ConversionRunner permutedRunner; + internal ConversionRunner permutedRunnerRgbaToArgb; - [Params(32)] + [Params( + 256, + 2048 + )] public int Count { get; set; } [GlobalSetup] public void Setup() { this.compatibleMemLayoutRunner = new ConversionRunner(this.Count); - this.permutedRunner = new ConversionRunner(this.Count); + this.permutedRunnerRgbaToArgb = new ConversionRunner(this.Count); } + } + public class PixelConversion_ConvertFromRgba32_Compatible : PixelConversion_ConvertFromRgba32 + { [Benchmark(Baseline = true)] - public void CompatibleByRef() + public void ByRef() { this.compatibleMemLayoutRunner.RunByRefConversion(); } [Benchmark] - public void CompatibleByVal() + public void ByVal() { this.compatibleMemLayoutRunner.RunByValConversion(); } [Benchmark] - public void CompatibleFromBytes() + public void FromBytes() { this.compatibleMemLayoutRunner.RunFromBytesConversion(); } + [Benchmark] + public void Inline() + { + ref Rgba32 sBase = ref this.compatibleMemLayoutRunner.source[0]; + ref Rgba32 dBase = ref Unsafe.As(ref this.compatibleMemLayoutRunner.dest[0]); + + for (int i = 0; i < this.Count; i++) + { + Unsafe.Add(ref dBase, i) = Unsafe.Add(ref sBase, i); + } + } + + // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | + // ---------- |------ |---------:|---------:|---------:|-------:|---------:| + // ByRef | 256 | 128.5 ns | 1.217 ns | 1.138 ns | 1.00 | 0.00 | + // ByVal | 256 | 196.7 ns | 2.792 ns | 2.612 ns | 1.53 | 0.02 | + // FromBytes | 256 | 321.7 ns | 2.180 ns | 1.820 ns | 2.50 | 0.03 | + // Inline | 256 | 129.9 ns | 2.759 ns | 2.581 ns | 1.01 | 0.02 | + } + + public class PixelConversion_ConvertFromRgba32_Permuted_RgbaToArgb : PixelConversion_ConvertFromRgba32 + { + [Benchmark(Baseline = true)] + public void ByRef() + { + this.permutedRunnerRgbaToArgb.RunByRefConversion(); + } + + [Benchmark] + public void ByVal() + { + this.permutedRunnerRgbaToArgb.RunByValConversion(); + } + + [Benchmark] + public void FromBytes() + { + this.permutedRunnerRgbaToArgb.RunFromBytesConversion(); + } [Benchmark] - public void PermutedByRef() + public void InlineShuffle() { - this.permutedRunner.RunByRefConversion(); + ref Rgba32 sBase = ref this.permutedRunnerRgbaToArgb.source[0]; + ref TestArgb dBase = ref this.permutedRunnerRgbaToArgb.dest[0]; + + for (int i = 0; i < this.Count; i++) + { + Rgba32 s = Unsafe.Add(ref sBase, i); + ref TestArgb d = ref Unsafe.Add(ref dBase, i); + + d.R = s.R; + d.G = s.G; + d.B = s.B; + d.A = s.A; + } } [Benchmark] - public void PermutedByVal() + public void PixelConverter_Rgba32_ToArgb32() { - this.permutedRunner.RunByValConversion(); + ref uint sBase = ref Unsafe.As(ref this.permutedRunnerRgbaToArgb.source[0]); + ref uint dBase = ref Unsafe.As(ref this.permutedRunnerRgbaToArgb.dest[0]); + + for (int i = 0; i < this.Count; i++) + { + uint s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i) = PixelConverter.Rgba32.ToArgb32(s); + } } [Benchmark] - public void PermutedFromBytes() + public void PixelConverter_Rgba32_ToArgb32_CopyThenWorkOnSingleBuffer() { - this.permutedRunner.RunFromBytesConversion(); + Span source = MemoryMarshal.Cast(this.permutedRunnerRgbaToArgb.source); + Span dest = MemoryMarshal.Cast(this.permutedRunnerRgbaToArgb.dest); + source.CopyTo(dest); + + ref uint dBase = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < this.Count; i++) + { + uint s = Unsafe.Add(ref dBase, i); + Unsafe.Add(ref dBase, i) = PixelConverter.Rgba32.ToArgb32(s); + } } - } - /* - * Results: - * Method | Count | Mean | StdDev | Scaled | Scaled-StdDev | - * ------------------ |------ |----------- |---------- |------- |-------------- | - * CompatibleByRef | 32 | 20.6339 ns | 0.0742 ns | 1.00 | 0.00 | - * CompatibleByVal | 32 | 23.7425 ns | 0.0997 ns | 1.15 | 0.01 | - * CompatibleFromBytes | 32 | 38.7017 ns | 0.1103 ns | 1.88 | 0.01 | - * PermutedByRef | 32 | 39.2892 ns | 0.1366 ns | 1.90 | 0.01 | - * PermutedByVal | 32 | 38.5178 ns | 0.1946 ns | 1.87 | 0.01 | - * PermutedFromBytes | 32 | 38.6683 ns | 0.0801 ns | 1.87 | 0.01 | - * - * !!! Conclusion !!! - * All memory-incompatible (permuted) variants are equivalent with the the "FromBytes" solution. - * In memory compatible cases we should use the optimized Bulk-copying variant anyways, - * so there is no benefit introducing non-bulk API-s other than FromBytes() OR FromRgba32(). - */ + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | + // ---------------------------------------------------------- |------ |-----------:|-----------:|-----------:|-------:|---------:| + // ByRef | 256 | 328.7 ns | 6.6141 ns | 6.1868 ns | 1.00 | 0.00 | + // ByVal | 256 | 322.0 ns | 4.3541 ns | 4.0728 ns | 0.98 | 0.02 | + // FromBytes | 256 | 321.5 ns | 3.3499 ns | 3.1335 ns | 0.98 | 0.02 | + // InlineShuffle | 256 | 330.7 ns | 4.2525 ns | 3.9778 ns | 1.01 | 0.02 | + // PixelConverter_Rgba32_ToArgb32 | 256 | 167.4 ns | 0.6357 ns | 0.5309 ns | 0.51 | 0.01 | + // PixelConverter_Rgba32_ToArgb32_CopyThenWorkOnSingleBuffer | 256 | 196.6 ns | 0.8929 ns | 0.7915 ns | 0.60 | 0.01 | + // | | | | | | | + // ByRef | 2048 | 2,534.4 ns | 8.2947 ns | 6.9265 ns | 1.00 | 0.00 | + // ByVal | 2048 | 2,638.5 ns | 52.6843 ns | 70.3320 ns | 1.04 | 0.03 | + // FromBytes | 2048 | 2,517.2 ns | 40.8055 ns | 38.1695 ns | 0.99 | 0.01 | + // InlineShuffle | 2048 | 2,546.5 ns | 21.2506 ns | 19.8778 ns | 1.00 | 0.01 | + // PixelConverter_Rgba32_ToArgb32 | 2048 | 1,265.7 ns | 5.1397 ns | 4.5562 ns | 0.50 | 0.00 | + // PixelConverter_Rgba32_ToArgb32_CopyThenWorkOnSingleBuffer | 2048 | 1,410.3 ns | 11.1939 ns | 9.9231 ns | 0.56 | 0.00 |// + } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs index 61a7df81d6..76de794eca 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs @@ -9,81 +9,81 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion [StructLayout(LayoutKind.Sequential)] struct TestArgb : ITestPixel { - private byte a, r, g, b; + public byte A, R, G, B; [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromRgba32(Rgba32 p) { - this.r = p.R; - this.g = p.G; - this.b = p.B; - this.a = p.A; + this.R = p.R; + this.G = p.G; + this.B = p.B; + this.A = p.A; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromRgba32(ref Rgba32 p) { - this.r = p.R; - this.g = p.G; - this.b = p.B; - this.a = p.A; + this.R = p.R; + this.G = p.G; + this.B = p.B; + this.A = p.A; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromBytes(byte r, byte g, byte b, byte a) { - this.r = r; - this.g = g; - this.b = b; - this.a = a; + this.R = r; + this.G = g; + this.B = b; + this.A = a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromVector4(Vector4 p) { - this.r = (byte)p.X; - this.g = (byte)p.Y; - this.b = (byte)p.Z; - this.a = (byte)p.W; + this.R = (byte)p.X; + this.G = (byte)p.Y; + this.B = (byte)p.Z; + this.A = (byte)p.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromVector4(ref Vector4 p) { - this.r = (byte)p.X; - this.g = (byte)p.Y; - this.b = (byte)p.Z; - this.a = (byte)p.W; + this.R = (byte)p.X; + this.G = (byte)p.Y; + this.B = (byte)p.Z; + this.A = (byte)p.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32 ToRgba32() { - return new Rgba32(this.r, this.g, this.b, this.a); + return new Rgba32(this.R, this.G, this.B, this.A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void CopyToRgba32(ref Rgba32 dest) { - dest.R = this.r; - dest.G = this.g; - dest.B = this.b; - dest.A = this.a; + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + dest.A = this.A; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 ToVector4() { - return new Vector4(this.r, this.g, this.b, this.a); + return new Vector4(this.R, this.G, this.B, this.A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void CopyToVector4(ref Vector4 dest) { - dest.X = this.r; - dest.Y = this.g; - dest.Z = this.b; - dest.W = this.a; + dest.X = this.R; + dest.Y = this.G; + dest.Z = this.B; + dest.W = this.A; } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs index cc8cf352a8..36d5f3e5b9 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion [StructLayout(LayoutKind.Sequential)] struct TestRgba : ITestPixel { - private byte r, g, b, a; + public byte R, G, B, A; [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromRgba32(Rgba32 source) @@ -26,10 +26,10 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromBytes(byte r, byte g, byte b, byte a) { - this.r = r; - this.g = g; - this.b = b; - this.a = a; + this.R = r; + this.G = g; + this.B = b; + this.A = a; } public void FromVector4(Vector4 source) @@ -57,13 +57,13 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 ToVector4() { - return new Vector4(this.r, this.g, this.b, this.a) * new Vector4(1f / 255f); + return new Vector4(this.R, this.G, this.B, this.A) * new Vector4(1f / 255f); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void CopyToVector4(ref Vector4 dest) { - var tmp = new Vector4(this.r, this.g, this.b, this.a); + var tmp = new Vector4(this.R, this.G, this.B, this.A); tmp *= new Vector4(1f / 255f); dest = tmp; } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs new file mode 100644 index 0000000000..83c4e34f2f --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs @@ -0,0 +1,150 @@ +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; + +namespace SixLabors.ImageSharp.Tests.PixelFormats +{ + public class PixelConverterTests + { + public static readonly TheoryData RgbaData = + new TheoryData + { + { 0, 0, 0, 0 }, + { 0, 0, 0, 255 }, + { 0, 0, 255, 0 }, + { 0, 255, 0, 0 }, + { 255, 0, 0, 0 }, + { 255, 255, 255, 255 }, + { 0, 0, 0, 1 }, + { 0, 0, 1, 0 }, + { 0, 1, 0, 0 }, + { 1, 0, 0, 0 }, + { 3, 5, 7, 11 }, + { 67, 71, 101, 109 } + }; + + [Theory] + [MemberData(nameof(RgbaData))] + public void Rgba32ToArgb32(byte r, byte g, byte b, byte a) + { + Rgba32 s = ReferenceImplementations.MakeRgba32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.Rgba32.ToArgb32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.ToArgb32(s).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } + + [Theory] + [MemberData(nameof(RgbaData))] + public void Argb32ToRgba32(byte r, byte g, byte b, byte a) + { + Argb32 s = ReferenceImplementations.MakeArgb32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.Argb32.ToRgba32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.ToRgba32(s).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } + + + private static class ReferenceImplementations + { + public static Rgba32 MakeRgba32(byte r, byte g, byte b, byte a) + { + Rgba32 d = default; + d.R = r; + d.G = g; + d.B = b; + d.A = a; + return d; + } + + public static Argb32 MakeArgb32(byte r, byte g, byte b, byte a) + { + Argb32 d = default; + d.R = r; + d.G = g; + d.B = b; + d.A = a; + return d; + } + + public static Bgra32 MakeBgra32(byte r, byte g, byte b, byte a) + { + Bgra32 d = default; + d.R = r; + d.G = g; + d.B = b; + d.A = a; + return d; + } + + public static Argb32 ToArgb32(Rgba32 s) + { + Argb32 d = default; + d.R = s.R; + d.G = s.G; + d.B = s.B; + d.A = s.A; + return d; + } + + public static Argb32 ToArgb32(Bgra32 s) + { + Argb32 d = default; + d.R = s.R; + d.G = s.G; + d.B = s.B; + d.A = s.A; + return d; + } + + public static Rgba32 ToRgba32(Argb32 s) + { + Rgba32 d = default; + d.R = s.R; + d.G = s.G; + d.B = s.B; + d.A = s.A; + return d; + } + + public static Rgba32 ToRgba32(Bgra32 s) + { + Rgba32 d = default; + d.R = s.R; + d.G = s.G; + d.B = s.B; + d.A = s.A; + return d; + } + + public static Bgra32 ToBgra32(Rgba32 s) + { + Bgra32 d = default; + d.R = s.R; + d.G = s.G; + d.B = s.B; + d.A = s.A; + return d; + } + + public static Bgra32 ToBgra32(Argb32 s) + { + Bgra32 d = default; + d.R = s.R; + d.G = s.G; + d.B = s.B; + d.A = s.A; + return d; + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs index 8c702f66da..ad1d137406 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs @@ -5,6 +5,7 @@ using System; using System.Numerics; using SixLabors.ImageSharp.PixelFormats; using Xunit; +using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests.PixelFormats { From 15415ef3c4bb6f34856eba961fd28c438ba58db5 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 23 Oct 2018 19:03:03 +0200 Subject: [PATCH 215/381] Update xmldoc --- src/ImageSharp/PixelFormats/IPixel.cs | 36 +++++++++---------- .../PixelFormats/PixelOperations{TPixel}.cs | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index 13e35cce05..1277406869 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -24,93 +24,93 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// An interface that represents a pixel type. + /// A base interface for all pixels, defining the mandatory operations to be implemented by a pixel type. /// public interface IPixel { /// - /// Sets the packed representation from a scaled . + /// Initializes the pixel instance from a generic ("scaled") . /// - /// The vector to create the packed representation from. + /// The vector to load the pixel from. void FromScaledVector4(Vector4 vector); /// - /// Expands the packed representation into a scaled - /// with values clamped between 0 and 1. + /// Expands the pixel into a generic ("scaled") representation + /// with values scaled and clamped between 0 and 1. /// The vector components are typically expanded in least to greatest significance order. /// /// The . Vector4 ToScaledVector4(); /// - /// Sets the packed representation from a . + /// Initializes the pixel instance from a which is specific to the current pixel type. /// - /// The vector to create the packed representation from. + /// The vector to load the pixel from. void FromVector4(Vector4 vector); /// - /// Expands the packed representation into a . + /// Expands the pixel into a which is specific to the current pixel type. /// The vector components are typically expanded in least to greatest significance order. /// /// The . Vector4 ToVector4(); /// - /// Packs the pixel from an value. + /// Initializes the pixel instance from an value. /// /// The value. void FromArgb32(Argb32 source); /// - /// Packs the pixel from an value. + /// Initializes the pixel instance from an value. /// /// The value. void FromBgr24(Bgr24 source); /// - /// Packs the pixel from an value. + /// Initializes the pixel instance from an value. /// /// The value. void FromBgra32(Bgra32 source); /// - /// Packs the Pixel from an value. + /// Initializes the pixel instance from an value. /// /// The value. void FromGray8(Gray8 source); /// - /// Packs the Pixel from an value. + /// Initializes the pixel instance from an value. /// /// The value. void FromGray16(Gray16 source); /// - /// Packs the pixel from an value. + /// Initializes the pixel instance from an value. /// /// The value. void FromRgb24(Rgb24 source); /// - /// Packs the pixel from an value. + /// Initializes the pixel instance from an value. /// /// The value. void FromRgba32(Rgba32 source); /// - /// Expands the packed representation into an . + /// Convert the pixel instance into representation. /// /// The reference to the destination pixel void ToRgba32(ref Rgba32 dest); /// - /// Packs the pixel from an value. + /// Initializes the pixel instance from an value. /// /// The value. void FromRgb48(Rgb48 source); /// - /// Packs the pixel from an value. + /// Initializes the pixel instance from an value. /// /// The value. void FromRgba64(Rgba64 source); diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 510645c4e9..126db85335 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.PixelFormats return; } - // Normal converson + // Normal conversion ref TDestinationPixel destRef = ref MemoryMarshal.GetReference(destinationColors); for (int i = 0; i < count; i++) { From 96d0ae80b9b743ca8e67435e40ba7ff9c0937b75 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 23 Oct 2018 20:14:05 +0200 Subject: [PATCH 216/381] Rgba32 <-> Argb32 <-> Bgra32 --- src/ImageSharp/PixelFormats/PixelConverter.cs | 76 +++++++- .../PixelFormats/PixelOperations{TPixel}.cs | 22 --- .../PixelConversion_ConvertFromRgba32.cs | 4 +- .../PixelFormats/PixelConverterTests.cs | 167 +++++++++--------- 4 files changed, 158 insertions(+), 111 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelConverter.cs b/src/ImageSharp/PixelFormats/PixelConverter.cs index 3686092cd2..8fde490fda 100644 --- a/src/ImageSharp/PixelFormats/PixelConverter.cs +++ b/src/ImageSharp/PixelFormats/PixelConverter.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers.Binary; using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.PixelFormats @@ -16,32 +17,91 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal static class PixelConverter { - public static class Rgba32 + public static class FromRgba32 { /// - /// Converts a packed to . + /// Converts a packed to . /// [MethodImpl(InliningOptions.ShortMethod)] public static uint ToArgb32(uint packedRgba) { - // packedRgba = [aa bb gg rr] - // ROL(8, packedRgba): + // packedRgba = [aa bb gg rr] + // ROL(8, packedRgba) = [bb gg rr aa] return (packedRgba << 8) | (packedRgba >> 24); } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToBgra32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // tmp1 = [aa 00 gg 00] + // tmp2 = [00 bb 00 rr] + // tmp3=ROL(16, tmp2) = [00 rr 00 bb] + // tmp1 + tmp3 = [aa rr gg bb] + uint tmp1 = packedRgba & 0xFF00FF00; + uint tmp2 = packedRgba & 0x00FF00FF; + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + return tmp1 + tmp3; + } } - public static class Argb32 + public static class FromArgb32 { /// - /// Converts a packed to . + /// Converts a packed to . /// [MethodImpl(InliningOptions.ShortMethod)] public static uint ToRgba32(uint packedArgb) { - // packedArgb = [bb gg rr aa] - // ROR(8, packedArgb): + // packedArgb = [bb gg rr aa] + // ROR(8, packedArgb) = [aa bb gg rr] return (packedArgb >> 8) | (packedArgb << 24); } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToBgra32(uint packedArgb) + { + // packedArgb = [bb gg rr aa] + // REVERSE(packedArgb) = [aa rr gg bb] + return BinaryPrimitives.ReverseEndianness(packedArgb); + } + } + + public static class FromBgra32 + { + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToArgb32(uint packedBgra) + { + // packedBgra = [aa rr gg bb] + // REVERSE(packedBgra) = [bb gg rr aa] + return BinaryPrimitives.ReverseEndianness(packedBgra); + } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToRgba32(uint packedBgra) + { + // packedRgba = [aa rr gg bb] + // tmp1 = [aa 00 gg 00] + // tmp2 = [00 rr 00 bb] + // tmp3=ROL(16, tmp2) = [00 bb 00 rr] + // tmp1 + tmp3 = [aa bb gg rr] + uint tmp1 = packedBgra & 0xFF00FF00; + uint tmp2 = packedBgra & 0x00FF00FF; + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + return tmp1 + tmp3; + } } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 02b80de9b4..ad5aee8c7c 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -178,27 +178,5 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromScaledVector4(sp.ToScaledVector4()); } } - - /// - /// Verifies that the given 'source' and 'destination' 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 - protected internal static void GuardSpans( - ReadOnlySpan source, - string sourceParamName, - Span destination, - string destinationParamName, - int minLength) - { - Guard.MustBeSizedAtLeast(source, minLength, sourceParamName); - Guard.MustBeSizedAtLeast(destination, minLength, destinationParamName); - } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs index 1be8347c3d..424020e2f2 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs @@ -174,7 +174,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion for (int i = 0; i < this.Count; i++) { uint s = Unsafe.Add(ref sBase, i); - Unsafe.Add(ref dBase, i) = PixelConverter.Rgba32.ToArgb32(s); + Unsafe.Add(ref dBase, i) = PixelConverter.FromRgba32.ToArgb32(s); } } @@ -190,7 +190,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion for (int i = 0; i < this.Count; i++) { uint s = Unsafe.Add(ref dBase, i); - Unsafe.Add(ref dBase, i) = PixelConverter.Rgba32.ToArgb32(s); + Unsafe.Add(ref dBase, i) = PixelConverter.FromRgba32.ToArgb32(s); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs index 83c4e34f2f..9b32f7aeee 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs @@ -4,7 +4,7 @@ using Xunit; namespace SixLabors.ImageSharp.Tests.PixelFormats { - public class PixelConverterTests + public abstract class PixelConverterTests { public static readonly TheoryData RgbaData = new TheoryData @@ -23,34 +23,103 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { 67, 71, 101, 109 } }; - [Theory] - [MemberData(nameof(RgbaData))] - public void Rgba32ToArgb32(byte r, byte g, byte b, byte a) + public class FromRgba32 : PixelConverterTests { - Rgba32 s = ReferenceImplementations.MakeRgba32(r, g, b, a); + [Theory] + [MemberData(nameof(RgbaData))] + public void ToArgb32(byte r, byte g, byte b, byte a) + { + Rgba32 s = ReferenceImplementations.MakeRgba32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromRgba32.ToArgb32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeArgb32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } + + [Theory] + [MemberData(nameof(RgbaData))] + public void ToBgra32(byte r, byte g, byte b, byte a) + { + Rgba32 s = ReferenceImplementations.MakeRgba32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromRgba32.ToBgra32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeBgra32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } + } + + public class FromArgb32 : PixelConverterTests + { + [Theory] + [MemberData(nameof(RgbaData))] + public void ToRgba32(byte r, byte g, byte b, byte a) + { + Argb32 s = ReferenceImplementations.MakeArgb32(r, g, b, a); - // Act: - uint actualPacked = PixelConverter.Rgba32.ToArgb32(s.PackedValue); + // Act: + uint actualPacked = PixelConverter.FromArgb32.ToRgba32(s.PackedValue); - // Assert: - uint expectedPacked = ReferenceImplementations.ToArgb32(s).PackedValue; + // Assert: + uint expectedPacked = ReferenceImplementations.MakeRgba32(r, g, b, a).PackedValue; - Assert.Equal(expectedPacked, actualPacked); + Assert.Equal(expectedPacked, actualPacked); + } + + [Theory] + [MemberData(nameof(RgbaData))] + public void ToBgra32(byte r, byte g, byte b, byte a) + { + Argb32 s = ReferenceImplementations.MakeArgb32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromArgb32.ToBgra32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeBgra32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } } - [Theory] - [MemberData(nameof(RgbaData))] - public void Argb32ToRgba32(byte r, byte g, byte b, byte a) + public class FromBgra32 : PixelConverterTests { - Argb32 s = ReferenceImplementations.MakeArgb32(r, g, b, a); + [Theory] + [MemberData(nameof(RgbaData))] + public void ToArgb32(byte r, byte g, byte b, byte a) + { + Bgra32 s = ReferenceImplementations.MakeBgra32(r, g, b, a); - // Act: - uint actualPacked = PixelConverter.Argb32.ToRgba32(s.PackedValue); + // Act: + uint actualPacked = PixelConverter.FromBgra32.ToArgb32(s.PackedValue); - // Assert: - uint expectedPacked = ReferenceImplementations.ToRgba32(s).PackedValue; + // Assert: + uint expectedPacked = ReferenceImplementations.MakeArgb32(r, g, b, a).PackedValue; - Assert.Equal(expectedPacked, actualPacked); + Assert.Equal(expectedPacked, actualPacked); + } + + [Theory] + [MemberData(nameof(RgbaData))] + public void ToRgba32(byte r, byte g, byte b, byte a) + { + Bgra32 s = ReferenceImplementations.MakeBgra32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromBgra32.ToRgba32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeRgba32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } } @@ -85,66 +154,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats d.A = a; return d; } - - public static Argb32 ToArgb32(Rgba32 s) - { - Argb32 d = default; - d.R = s.R; - d.G = s.G; - d.B = s.B; - d.A = s.A; - return d; - } - - public static Argb32 ToArgb32(Bgra32 s) - { - Argb32 d = default; - d.R = s.R; - d.G = s.G; - d.B = s.B; - d.A = s.A; - return d; - } - - public static Rgba32 ToRgba32(Argb32 s) - { - Rgba32 d = default; - d.R = s.R; - d.G = s.G; - d.B = s.B; - d.A = s.A; - return d; - } - - public static Rgba32 ToRgba32(Bgra32 s) - { - Rgba32 d = default; - d.R = s.R; - d.G = s.G; - d.B = s.B; - d.A = s.A; - return d; - } - - public static Bgra32 ToBgra32(Rgba32 s) - { - Bgra32 d = default; - d.R = s.R; - d.G = s.G; - d.B = s.B; - d.A = s.A; - return d; - } - - public static Bgra32 ToBgra32(Argb32 s) - { - Bgra32 d = default; - d.R = s.R; - d.G = s.G; - d.B = s.B; - d.A = s.A; - return d; - } } } } \ No newline at end of file From d5cae6987bffbba1de98269842497a548429a5ec Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 23 Oct 2018 23:34:24 +0200 Subject: [PATCH 217/381] disappointing benchmark for Rgba32 -> Bgra32 --- .../PixelConversion_Rgba32_To_Argb32.cs | 278 +++++++++++++ .../PixelConversion_Rgba32_To_Bgra32.cs | 393 ++++++++++++++++++ 2 files changed, 671 insertions(+) create mode 100644 tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs create mode 100644 tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs new file mode 100644 index 0000000000..5190145276 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs @@ -0,0 +1,278 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + public class PixelConversion_Rgba32_To_Argb32 + { + private Rgba32[] source; + + private Argb32[] dest; + + [Params(64)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.source = new Rgba32[this.Count]; + this.dest = new Argb32[this.Count]; + } + + [Benchmark(Baseline = true)] + public void Default() + { + ref Rgba32 sBase = ref this.source[0]; + ref Argb32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count; i++) + { + Rgba32 s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i).FromRgba32(s); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void Default_GenericImpl(ReadOnlySpan source, Span dest) + where TPixel : struct, IPixel + { + ref Rgba32 sBase = ref MemoryMarshal.GetReference(source); + ref TPixel dBase = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < source.Length; i++) + { + Rgba32 s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i).FromRgba32(s); + } + } + + [Benchmark] + public void Default_Generic() + { + Default_GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); + } + + [Benchmark] + public void Default_Group2() + { + ref Rgba32 sBase = ref this.source[0]; + ref Argb32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count / 2; i += 2) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + Rgba32 s1 = Unsafe.Add(ref s0, 1); + + ref Argb32 d0 = ref Unsafe.Add(ref dBase, i); + d0.FromRgba32(s0); + Unsafe.Add(ref d0, 1).FromRgba32(s1); + } + } + + + [Benchmark] + public void Default_Group4() + { + ref Rgba32 sBase = ref this.source[0]; + ref Argb32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count / 4; i += 4) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); + ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); + Rgba32 s3 = Unsafe.Add(ref s2, 1); + + ref Argb32 d0 = ref Unsafe.Add(ref dBase, i); + ref Argb32 d1 = ref Unsafe.Add(ref d0, 1); + ref Argb32 d2 = ref Unsafe.Add(ref d1, 1); + + d0.FromRgba32(s0); + d1.FromRgba32(s1); + d2.FromRgba32(s2); + Unsafe.Add(ref d2, 1).FromRgba32(s3); + } + } + + [Benchmark] + public void Default_Group4_ManualInline_V1() + { + ref Rgba32 sBase = ref this.source[0]; + ref Argb32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count / 4; i += 4) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); + ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); + Rgba32 s3 = Unsafe.Add(ref s2, 1); + + ref Argb32 d0 = ref Unsafe.Add(ref dBase, i); + ref Argb32 d1 = ref Unsafe.Add(ref d0, 1); + ref Argb32 d2 = ref Unsafe.Add(ref d1, 1); + ref Argb32 d3 = ref Unsafe.Add(ref d2, 1); + + d0.R = s0.R; + d0.G = s0.G; + d0.B = s0.B; + d0.A = s0.A; + + d1.R = s1.R; + d1.G = s1.G; + d1.B = s1.B; + d1.A = s1.A; + + d2.R = s2.R; + d2.G = s2.G; + d2.B = s2.B; + d2.A = s2.A; + + d3.R = s3.R; + d3.G = s3.G; + d3.B = s3.B; + d3.A = s3.A; + } + } + + [Benchmark] + public void Default_Group4_ManualInline_V2() + { + ref Rgba32 sBase = ref this.source[0]; + ref Argb32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count / 4; i += 4) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); + ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); + Rgba32 s3 = Unsafe.Add(ref s2, 1); + + ref Argb32 d0 = ref Unsafe.Add(ref dBase, i); + ref Argb32 d1 = ref Unsafe.Add(ref d0, 1); + ref Argb32 d2 = ref Unsafe.Add(ref d1, 1); + ref Argb32 d3 = ref Unsafe.Add(ref d2, 1); + + d0.R = s0.R; + d1.R = s1.R; + d2.R = s2.R; + d3.R = s3.R; + + d0.G = s0.G; + d1.G = s1.G; + d2.G = s2.G; + d3.G = s3.G; + + d0.B = s0.B; + d1.B = s1.B; + d2.B = s2.B; + d3.B = s3.B; + + d0.A = s0.A; + d1.A = s1.A; + d2.A = s2.A; + d3.A = s3.A; + } + } + + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void Group4GenericImpl(ReadOnlySpan source, Span dest) + where TPixel : struct, IPixel + { + ref Rgba32 sBase = ref MemoryMarshal.GetReference(source); + ref TPixel dBase = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < source.Length / 4; i += 4) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); + ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); + Rgba32 s3 = Unsafe.Add(ref s2, 1); + + ref TPixel d0 = ref Unsafe.Add(ref dBase, i); + ref TPixel d1 = ref Unsafe.Add(ref d0, 1); + ref TPixel d2 = ref Unsafe.Add(ref d1, 1); + + d0.FromRgba32(s0); + d1.FromRgba32(s1); + d2.FromRgba32(s2); + Unsafe.Add(ref d2, 1).FromRgba32(s3); + } + } + + [Benchmark] + public void Default_Group4_Generic() + { + Group4GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); + } + + [Benchmark] + public void BitOps() + { + ref uint sBase = ref Unsafe.As(ref this.source[0]); + ref uint dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count; i++) + { + uint s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i) = FromRgba32.ToArgb32(s); + } + } + + [Benchmark] + public void BitOps_GroupAsULong() + { + ref ulong sBase = ref Unsafe.As(ref this.source[0]); + ref ulong dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count / 2; i++) + { + ulong s = Unsafe.Add(ref sBase, i); + uint lo = (uint)s; + uint hi = (uint)(s >> 32); + lo = FromRgba32.ToArgb32(lo); + hi = FromRgba32.ToArgb32(hi); + + s = (ulong)(hi << 32) | lo; + + Unsafe.Add(ref dBase, i) = s; + } + } + + public static class FromRgba32 + { + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToArgb32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // ROL(8, packedRgba) = [bb gg rr aa] + return (packedRgba << 8) | (packedRgba >> 24); + } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToBgra32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // tmp1 = [aa 00 gg 00] + // tmp2 = [00 bb 00 rr] + // tmp3=ROL(16, tmp2) = [00 rr 00 bb] + // tmp1 + tmp3 = [aa rr gg bb] + uint tmp1 = packedRgba & 0xFF00FF00; + uint tmp2 = packedRgba & 0x00FF00FF; + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + return tmp1 + tmp3; + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs new file mode 100644 index 0000000000..9e638dbcc4 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs @@ -0,0 +1,393 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes.Jobs; + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tuples; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + //[MonoJob] + [RyuJitX64Job] + public class PixelConversion_Rgba32_To_Bgra32 + { + private Rgba32[] source; + + private Bgra32[] dest; + + [StructLayout(LayoutKind.Sequential)] + struct Tuple4OfUInt32 + { + public uint V0, V1, V2, V3; + + public void ConvertMe() + { + this.V0 = FromRgba32.ToBgra32(this.V0); + this.V1 = FromRgba32.ToBgra32(this.V1); + this.V2 = FromRgba32.ToBgra32(this.V2); + this.V3 = FromRgba32.ToBgra32(this.V3); + } + } + + [Params(64)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.source = new Rgba32[this.Count]; + this.dest = new Bgra32[this.Count]; + } + + [Benchmark(Baseline = true)] + public void Default() + { + ref Rgba32 sBase = ref this.source[0]; + ref Bgra32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count; i++) + { + Rgba32 s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i).FromRgba32(s); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void Default_GenericImpl(ReadOnlySpan source, Span dest) + where TPixel : struct, IPixel + { + ref Rgba32 sBase = ref MemoryMarshal.GetReference(source); + ref TPixel dBase = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < source.Length; i++) + { + Rgba32 s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i).FromRgba32(s); + } + } + + [Benchmark] + public void Default_Generic() + { + Default_GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); + } + + [Benchmark] + public void Default_Group2() + { + ref Rgba32 sBase = ref this.source[0]; + ref Bgra32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count / 2; i+=2) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + Rgba32 s1 = Unsafe.Add(ref s0, 1); + + ref Bgra32 d0 = ref Unsafe.Add(ref dBase, i); + d0.FromRgba32(s0); + Unsafe.Add(ref d0, 1).FromRgba32(s1); + } + } + + [Benchmark] + public void Default_Group4() + { + ref Rgba32 sBase = ref this.source[0]; + ref Bgra32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count / 4; i += 4) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); + ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); + Rgba32 s3 = Unsafe.Add(ref s2, 1); + + ref Bgra32 d0 = ref Unsafe.Add(ref dBase, i); + ref Bgra32 d1 = ref Unsafe.Add(ref d0, 1); + ref Bgra32 d2 = ref Unsafe.Add(ref d1, 1); + + d0.FromRgba32(s0); + d1.FromRgba32(s1); + d2.FromRgba32(s2); + Unsafe.Add(ref d2, 1).FromRgba32(s3); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void Group4GenericImpl(ReadOnlySpan source, Span dest) + where TPixel : struct, IPixel + { + ref Rgba32 sBase = ref MemoryMarshal.GetReference(source); + ref TPixel dBase = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < source.Length / 4; i += 4) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); + ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); + Rgba32 s3 = Unsafe.Add(ref s2, 1); + + ref TPixel d0 = ref Unsafe.Add(ref dBase, i); + ref TPixel d1 = ref Unsafe.Add(ref d0, 1); + ref TPixel d2 = ref Unsafe.Add(ref d1, 1); + + d0.FromRgba32(s0); + d1.FromRgba32(s1); + d2.FromRgba32(s2); + Unsafe.Add(ref d2, 1).FromRgba32(s3); + } + } + + [Benchmark] + public void Default_Group4_Generic() + { + Group4GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); + } + + //[Benchmark] + public void Default_Group8() + { + ref Rgba32 sBase = ref this.source[0]; + ref Bgra32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count / 4; i += 4) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); + ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); + ref Rgba32 s3 = ref Unsafe.Add(ref s1, 1); + + ref Rgba32 s4 = ref Unsafe.Add(ref s3, 1); + ref Rgba32 s5 = ref Unsafe.Add(ref s4, 1); + ref Rgba32 s6 = ref Unsafe.Add(ref s5, 1); + Rgba32 s7 = Unsafe.Add(ref s6, 1); + + ref Bgra32 d0 = ref Unsafe.Add(ref dBase, i); + ref Bgra32 d1 = ref Unsafe.Add(ref d0, 1); + ref Bgra32 d2 = ref Unsafe.Add(ref d1, 1); + ref Bgra32 d3 = ref Unsafe.Add(ref d2, 1); + ref Bgra32 d4 = ref Unsafe.Add(ref d3, 1); + + ref Bgra32 d5 = ref Unsafe.Add(ref d4, 1); + ref Bgra32 d6 = ref Unsafe.Add(ref d5, 1); + + + d0.FromRgba32(s0); + d1.FromRgba32(s1); + d2.FromRgba32(s2); + d3.FromRgba32(s3); + + d4.FromRgba32(s4); + d5.FromRgba32(s5); + d6.FromRgba32(s6); + Unsafe.Add(ref d6, 1).FromRgba32(s7); + } + } + + [Benchmark] + public void BitOps() + { + ref uint sBase = ref Unsafe.As(ref this.source[0]); + ref uint dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count; i++) + { + uint s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i) = FromRgba32.ToBgra32(s); + } + } + + [Benchmark] + public void Bitops_Tuple() + { + ref Tuple4OfUInt32 sBase = ref Unsafe.As(ref this.source[0]); + ref Tuple4OfUInt32 dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count / 4; i++) + { + ref Tuple4OfUInt32 d = ref Unsafe.Add(ref dBase, i); + d = Unsafe.Add(ref sBase, i); + d.ConvertMe(); + } + } + + [Benchmark] + public void Bitops_SingleTuple() + { + ref Tuple4OfUInt32 sBase = ref Unsafe.As(ref this.source[0]); + + for (int i = 0; i < this.Count / 4; i++) + { + Unsafe.Add(ref sBase, i).ConvertMe(); + } + } + + [Benchmark] + public void Bitops_Simd() + { + ref Octet.OfUInt32 sBase = ref Unsafe.As(ref this.source[0]); + ref Octet.OfUInt32 dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count / 8; i++) + { + BitopsSimdImpl(ref Unsafe.Add(ref sBase, i), ref Unsafe.Add(ref dBase, i)); + } + } + + [StructLayout(LayoutKind.Sequential)] + struct B + { + public uint tmp2, tmp5, tmp8, tmp11, tmp14, tmp17, tmp20, tmp23; + } + + [StructLayout(LayoutKind.Sequential)] + struct C + { + public uint tmp3, tmp6, tmp9, tmp12, tmp15, tmp18, tmp21, tmp24; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void BitopsSimdImpl(ref Octet.OfUInt32 s, ref Octet.OfUInt32 d) + { + Vector sVec = Unsafe.As>(ref s); + Vector aMask = new Vector(0xFF00FF00); + Vector bMask = new Vector(0x00FF00FF); + + Vector aa = sVec & aMask; + Vector bb = sVec & bMask; + + B b = Unsafe.As, B>(ref bb); + + C c = default; + + c.tmp3 = (b.tmp2 << 16) | (b.tmp2 >> 16); + c.tmp6 = (b.tmp5 << 16) | (b.tmp5 >> 16); + c.tmp9 = (b.tmp8 << 16) | (b.tmp8 >> 16); + c.tmp12 = (b.tmp11 << 16) | (b.tmp11 >> 16); + c.tmp15 = (b.tmp14 << 16) | (b.tmp14 >> 16); + c.tmp18 = (b.tmp17 << 16) | (b.tmp17 >> 16); + c.tmp21 = (b.tmp20 << 16) | (b.tmp20 >> 16); + c.tmp24 = (b.tmp23 << 16) | (b.tmp23 >> 16); + + Vector cc = Unsafe.As>(ref c); + Vector dd = aa + cc; + + d = Unsafe.As, Octet.OfUInt32>(ref dd); + } + + //[Benchmark] + public void BitOps_Group2() + { + ref uint sBase = ref Unsafe.As(ref this.source[0]); + ref uint dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count; i++) + { + ref uint s0 = ref Unsafe.Add(ref sBase, i); + uint s1 = Unsafe.Add(ref s0, 1); + + ref uint d0 = ref Unsafe.Add(ref dBase, i); + d0 = FromRgba32.ToBgra32(s0); + Unsafe.Add(ref d0, 1) = FromRgba32.ToBgra32(s1); + } + } + + [Benchmark] + public void BitOps_GroupAsULong() + { + ref ulong sBase = ref Unsafe.As(ref this.source[0]); + ref ulong dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count / 2; i++) + { + ulong s = Unsafe.Add(ref sBase, i); + uint lo = (uint)s; + uint hi = (uint)(s >> 32); + lo = FromRgba32.ToBgra32(lo); + hi = FromRgba32.ToBgra32(hi); + + s = (ulong)(hi << 32) | lo; + + Unsafe.Add(ref dBase, i) = s; + } + } + + //[Benchmark] + public void BitOps_GroupAsULong_V2() + { + ref ulong sBase = ref Unsafe.As(ref this.source[0]); + ref ulong dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count / 2; i++) + { + ulong s = Unsafe.Add(ref sBase, i); + uint lo = (uint)s; + uint hi = (uint)(s >> 32); + + uint tmp1 = lo & 0xFF00FF00; + uint tmp4 = hi & 0xFF00FF00; + + uint tmp2 = lo & 0x00FF00FF; + uint tmp5 = hi & 0x00FF00FF; + + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + uint tmp6 = (tmp5 << 16) | (tmp5 >> 16); + + lo = tmp1 + tmp3; + hi = tmp4 + tmp6; + + s = (ulong)(hi << 32) | lo; + + Unsafe.Add(ref dBase, i) = s; + } + } + + public static class FromRgba32 + { + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToArgb32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // ROL(8, packedRgba) = [bb gg rr aa] + return (packedRgba << 8) | (packedRgba >> 24); + } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToBgra32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // tmp1 = [aa 00 gg 00] + // tmp2 = [00 bb 00 rr] + // tmp3=ROL(16, tmp2) = [00 rr 00 bb] + // tmp1 + tmp3 = [aa rr gg bb] + uint tmp1 = packedRgba & 0xFF00FF00; + uint tmp2 = packedRgba & 0x00FF00FF; + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + return tmp1 + tmp3; + } + } + + + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | + // ----------------------- |------ |----------:|----------:|----------:|-------:| + // Default | 64 | 107.13 ns | 0.7752 ns | 0.6872 ns | 1.00 | + // Default_Generic | 64 | 113.78 ns | 0.7713 ns | 0.6022 ns | 1.06 | + // Default_Group2 | 64 | 43.72 ns | 0.1711 ns | 0.1600 ns | 0.41 | + // Default_Group4 | 64 | 23.47 ns | 0.1901 ns | 0.1588 ns | 0.22 | + // Default_Group4_Generic | 64 | 32.46 ns | 0.4297 ns | 0.4019 ns | 0.30 | + // Bitops_Tuple | 64 | 77.71 ns | 0.2779 ns | 0.2599 ns | 0.73 | + // Bitops_SingleTuple | 64 | 58.64 ns | 0.4511 ns | 0.4220 ns | 0.55 | + // Bitops_Simd | 64 | 110.58 ns | 0.4686 ns | 0.4383 ns | 1.03 | + } +} \ No newline at end of file From f52be32abafa7d164d9c31f2ce4851576c667ac9 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 23 Oct 2018 17:13:17 -0700 Subject: [PATCH 218/381] Cross target NET472 and enable extended intrinisics behind SUPPORTS_EXTENDED_INTRINSICS symbol --- .../Common/Helpers/SimdUtils.ExtendedIntrinsics.cs | 4 +--- src/ImageSharp/Common/Helpers/SimdUtils.cs | 4 ++-- src/ImageSharp/Common/Helpers/TestHelpers.cs | 6 +++++- src/ImageSharp/ImageSharp.csproj | 13 +++++++++---- tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 2 +- tests/ImageSharp.Tests/RunExtendedTests.cmd | 2 ++ 6 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index e0d6187dca..2ac577264c 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -20,8 +19,7 @@ namespace SixLabors.ImageSharp public static class ExtendedIntrinsics { public static bool IsAvailable { get; } = -#if NETCOREAPP2_1 - // TODO: Also available in .NET 4.7.2, we need to add a build target! +#if SUPPORTS_EXTENDED_INTRINSICS Vector.IsHardwareAccelerated; #else false; diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index 71eb88b1d1..a989cc8752 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); -#if NETCOREAPP2_1 +#if SUPPORTS_EXTENDED_INTRINSICS ExtendedIntrinsics.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); #else BasicIntrinsics256.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); @@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); -#if NETCOREAPP2_1 +#if SUPPORTS_EXTENDED_INTRINSICS ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); #else BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); diff --git a/src/ImageSharp/Common/Helpers/TestHelpers.cs b/src/ImageSharp/Common/Helpers/TestHelpers.cs index 45ef7706dd..fd16a577ab 100644 --- a/src/ImageSharp/Common/Helpers/TestHelpers.cs +++ b/src/ImageSharp/Common/Helpers/TestHelpers.cs @@ -13,8 +13,12 @@ namespace SixLabors.ImageSharp.Common.Helpers /// Only intended to be used in tests! /// internal const string ImageSharpBuiltAgainst = -#if NETCOREAPP2_1 +#if NET472 + "netfx4.7.2"; +#elif NETCOREAPP2_1 "netcoreapp2.1"; +#elif NETSTANDARD1_3 + "netstandard1.3"; #else "netstandard2.0"; #endif diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 8d2ad2abe3..29d29d50d8 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -5,7 +5,7 @@ $(packageversion) 0.0.1 Six Labors and contributors - netstandard1.3;netstandard2.0;netcoreapp2.1 + netstandard1.3;netstandard2.0;netcoreapp2.1;net472 true true SixLabors.ImageSharp @@ -31,9 +31,15 @@ IOperation Latest + + + $(DefineConstants);SUPPORTS_EXTENDED_INTRINSICS + + + @@ -43,15 +49,14 @@ - - - + + ..\..\ImageSharp.ruleset SixLabors.ImageSharp diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 5d163917cd..04a6802005 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -1,6 +1,6 @@  - net462;net471;netcoreapp2.1 + net462;net472;netcoreapp2.1 True latest full diff --git a/tests/ImageSharp.Tests/RunExtendedTests.cmd b/tests/ImageSharp.Tests/RunExtendedTests.cmd index 481e5fb3d8..c2f4b9f537 100644 --- a/tests/ImageSharp.Tests/RunExtendedTests.cmd +++ b/tests/ImageSharp.Tests/RunExtendedTests.cmd @@ -5,3 +5,5 @@ dotnet xunit -nobuild -c Release -f net47 dotnet xunit -nobuild -c Release -f net47 -x86 dotnet xunit -nobuild -c Release -f net471 dotnet xunit -nobuild -c Release -f net471 -x86 +dotnet xunit -nobuild -c Release -f net472 +dotnet xunit -nobuild -c Release -f net472 -x86 From 0e1efba34198e2a3cb204e53ce000c88f8f1bdbf Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 23 Oct 2018 17:30:30 -0700 Subject: [PATCH 219/381] Use Array.Empty --- .../Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs | 6 +++--- .../ICC/DataWriter/IccDataWriter.PrimitivesTests.cs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs b/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs index 38a2f4522c..77a913b14e 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// Initializes a new instance of the class. /// public IccCurveTagDataEntry() - : this(new float[0], IccProfileTag.Unknown) + : this(Array.Empty(), IccProfileTag.Unknown) { } @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// /// Tag Signature public IccCurveTagDataEntry(IccProfileTag tagSignature) - : this(new float[0], tagSignature) + : this(Array.Empty(), tagSignature) { } @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc public IccCurveTagDataEntry(float[] curveData, IccProfileTag tagSignature) : base(IccTypeSignature.Curve, tagSignature) { - this.CurveData = curveData ?? new float[0]; + this.CurveData = curveData ?? Array.Empty(); } /// diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.PrimitivesTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.PrimitivesTests.cs index 56a4f8c0ca..845a149b5d 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.PrimitivesTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.PrimitivesTests.cs @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Tests.Icc byte[] output = writer.GetData(); Assert.Equal(0, count); - Assert.Equal(new byte[0], output); + Assert.Equal(Array.Empty(), output); } [Fact] @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Tests.Icc byte[] output = writer.GetData(); Assert.Equal(0, count); - Assert.Equal(new byte[0], output); + Assert.Equal(Array.Empty(), output); } [Theory] From de0956295ad65c94f2d73cfbd20f52e7550a6306 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 23 Oct 2018 17:40:24 -0700 Subject: [PATCH 220/381] [Exif] Eliminate invalidTag list allocation when there are no invalid tags --- .../MetaData/Profiles/Exif/ExifProfile.cs | 12 +++++++++-- .../MetaData/Profiles/Exif/ExifReader.cs | 20 ++++++++++++++----- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs index b48b146f11..32c1796d4c 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif { this.Parts = ExifParts.All; this.data = data; - this.InvalidTags = new List(); + this.InvalidTags = Array.Empty(); } /// @@ -289,7 +289,15 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif this.values = reader.ReadValues(); - this.InvalidTags = new List(reader.InvalidTags); + if (reader.InvalidTags.Count > 0) + { + this.InvalidTags = new List(reader.InvalidTags); + } + else + { + this.InvalidTags = Array.Empty(); + } + this.thumbnailOffset = (int)reader.ThumbnailOffset; this.thumbnailLength = (int)reader.ThumbnailLength; } diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs index 5f95499088..3326c3217a 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs @@ -7,7 +7,6 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Text; using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.Primitives; @@ -19,7 +18,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// internal sealed class ExifReader { - private readonly List invalidTags = new List(); + private List invalidTags; private readonly byte[] exifData; private int position; private Endianness endianness = Endianness.BigEndian; @@ -38,7 +37,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// Gets the invalid tags. /// - public IReadOnlyList InvalidTags => this.invalidTags; + public IReadOnlyList InvalidTags => this.invalidTags ?? (IReadOnlyList)Array.Empty(); /// /// Gets the thumbnail length in the byte stream @@ -338,7 +337,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif // Ensure that the new index does not overrun the data if (newIndex > int.MaxValue) { - this.invalidTags.Add(tag); + this.AddInvalidTag(tag); exifValue = default; @@ -349,7 +348,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif if (this.RemainingLength < size) { - this.invalidTags.Add(tag); + this.AddInvalidTag(tag); + this.position = oldIndex; exifValue = default; @@ -372,6 +372,16 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return true; } + private void AddInvalidTag(ExifTag tag) + { + if (this.invalidTags == null) + { + this.invalidTags = new List(); + } + + this.invalidTags.Add(tag); + } + private TEnum ToEnum(int value, TEnum defaultValue) where TEnum : struct { From 2293494a77437ff004efdc4c3715049ca9bb37de Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 23 Oct 2018 17:45:47 -0700 Subject: [PATCH 221/381] Update IccProfile Entries to Array --- src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs | 11 ++++++----- src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs | 4 ++-- .../MetaData/Profiles/ICC/IccReaderTests.cs | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs index 72665bc69c..1d3b27c5ec 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Security.Cryptography; namespace SixLabors.ImageSharp.MetaData.Profiles.Icc @@ -20,7 +21,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// /// The backing file for the property /// - private List entries; + private IccTagDataEntry[] entries; /// /// ICC profile header @@ -52,7 +53,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc Guard.NotNull(entries, nameof(entries)); this.header = header; - this.entries = new List(entries); + this.entries = entries.ToArray(); } /// @@ -85,7 +86,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// /// Gets the actual profile data /// - public List Entries + public IccTagDataEntry[] Entries { get { @@ -212,12 +213,12 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc if (this.data is null) { - this.entries = new List(); + this.entries = Array.Empty(); return; } var reader = new IccReader(); - this.entries = new List(reader.ReadTagData(this.data)); + this.entries = 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 b476e31955..91a3bba549 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs @@ -68,12 +68,12 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc } } - private IccTagTableEntry[] WriteTagData(IccDataWriter writer, List entries) + private IccTagTableEntry[] WriteTagData(IccDataWriter writer, IccTagDataEntry[] entries) { IEnumerable> grouped = entries.GroupBy(t => t); // (Header size) + (entry count) + (nr of entries) * (size of table entry) - writer.SetIndex(128 + 4 + (entries.Count * 12)); + writer.SetIndex(128 + 4 + (entries.Length * 12)); var table = new List(); foreach (IGrouping group in grouped) diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccReaderTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccReaderTests.cs index b3215ee7ae..c91076afc9 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccReaderTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccReaderTests.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Tests.Icc IccProfile output = reader.Read(IccTestDataProfiles.Header_Random_Array); - Assert.Equal(0, output.Entries.Count); + Assert.Equal(0, output.Entries.Length); Assert.NotNull(output.Header); IccProfileHeader header = output.Header; @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Tests.Icc IccProfile output = reader.Read(IccTestDataProfiles.Profile_Random_Array); - Assert.Equal(2, output.Entries.Count); + Assert.Equal(2, output.Entries.Length); Assert.True(ReferenceEquals(output.Entries[0], output.Entries[1])); } From 41b5ef3061a3507c26e7c846a9e27bae2b3b9f18 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 23 Oct 2018 17:57:30 -0700 Subject: [PATCH 222/381] Eliminate an allocation when cloning a valid ExifProfile --- src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs index 32c1796d4c..6890cc5358 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs @@ -63,7 +63,16 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif this.Parts = other.Parts; this.thumbnailLength = other.thumbnailLength; this.thumbnailOffset = other.thumbnailOffset; - this.InvalidTags = new List(other.InvalidTags); + + if (other.InvalidTags.Count > 0) + { + this.InvalidTags = new List(other.InvalidTags); + } + else + { + this.InvalidTags = Array.Empty(); + } + if (other.values != null) { this.values = new List(other.Values.Count); From a80335d9e0a3af12db6f56bb94ccfbb4c354f5a9 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 23 Oct 2018 17:58:00 -0700 Subject: [PATCH 223/381] Eliminate allocation in invalid icc profile --- src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs index da47b565e3..9f9d373ae1 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccReader.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; namespace SixLabors.ImageSharp.MetaData.Profiles.Icc @@ -126,7 +127,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc // A normal profile usually has 5-15 entries if (tagCount > 100) { - return new IccTagTableEntry[0]; + return Array.Empty(); } var table = new List((int)tagCount); From 880ee68248c93d108e2c3598f78d9fc28ddbe2a2 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 23 Oct 2018 18:00:08 -0700 Subject: [PATCH 224/381] Update appveyor target frameworks --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 821fd427c8..34c733e68d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -15,7 +15,7 @@ environment: - target_framework: net471 is_32bit: False - - target_framework: net471 + - target_framework: net472 is_32bit: True - target_framework: net462 From bed5c6350581fba367162ee738c7ed5caae3fd4b Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 23 Oct 2018 18:00:41 -0700 Subject: [PATCH 225/381] Update appveyor target frameworks (64bit) --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 34c733e68d..2cc5182d39 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,7 +12,7 @@ environment: - target_framework: netcoreapp2.1 is_32bit: True - - target_framework: net471 + - target_framework: net472 is_32bit: False - target_framework: net472 From e2fe2b148b25dc47db0e6012639f3f164b38a74b Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 23 Oct 2018 18:07:24 -0700 Subject: [PATCH 226/381] Update IccProfile constructor --- src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs index 1d3b27c5ec..5d75a6df9d 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs @@ -2,8 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Collections.Generic; -using System.Linq; using System.Security.Cryptography; namespace SixLabors.ImageSharp.MetaData.Profiles.Icc @@ -47,13 +45,10 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// /// The profile header /// The actual profile data - internal IccProfile(IccProfileHeader header, IEnumerable entries) + internal IccProfile(IccProfileHeader header, IccTagDataEntry[] entries) { - Guard.NotNull(header, nameof(header)); - Guard.NotNull(entries, nameof(entries)); - - this.header = header; - this.entries = entries.ToArray(); + this.header = header ?? throw new ArgumentNullException(nameof(header)); + this.entries = entries ?? throw new ArgumentNullException(nameof(entries)); } /// From 5771f96382f882f0782b9221b98250977ba6cba8 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 23 Oct 2018 18:16:21 -0700 Subject: [PATCH 227/381] [Exif] Make allowedParts and values readonly --- src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs index ade373341e..9079526d5a 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs @@ -17,8 +17,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// Which parts will be written. /// - private ExifParts allowedParts; - private IList values; + private readonly ExifParts allowedParts; + private readonly IList values; private List dataOffsets; private readonly List ifdIndexes; private readonly List exifIndexes; From 3ac47cb4ed040efc8eb9fa352605784545292c97 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 23 Oct 2018 18:22:40 -0700 Subject: [PATCH 228/381] Use ternary operator --- .../MetaData/Profiles/Exif/ExifProfile.cs | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs index 6890cc5358..37ceaf10f6 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs @@ -64,14 +64,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif this.thumbnailLength = other.thumbnailLength; this.thumbnailOffset = other.thumbnailOffset; - if (other.InvalidTags.Count > 0) - { - this.InvalidTags = new List(other.InvalidTags); - } - else - { - this.InvalidTags = Array.Empty(); - } + this.InvalidTags = other.InvalidTags.Count > 0 + ? new List(other.InvalidTags) + : (IReadOnlyList)Array.Empty(); if (other.values != null) { @@ -298,14 +293,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif this.values = reader.ReadValues(); - if (reader.InvalidTags.Count > 0) - { - this.InvalidTags = new List(reader.InvalidTags); - } - else - { - this.InvalidTags = Array.Empty(); - } + this.InvalidTags = reader.InvalidTags.Count > 0 + ? new List(reader.InvalidTags) + : (IReadOnlyList)Array.Empty(); this.thumbnailOffset = (int)reader.ThumbnailOffset; this.thumbnailLength = (int)reader.ThumbnailLength; From 3dde4917124c90c891b790ec0806aa4c61e978f7 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 24 Oct 2018 01:49:26 +0200 Subject: [PATCH 229/381] Fixed the benchmarks. All results make sense now! (cherry picked from commit 0d79d4eb58fa1002979f4157eb18c6291a164b06) --- .../PixelConversion_Rgba32_To_Argb32.cs | 128 ++---------------- .../PixelConversion_Rgba32_To_Bgra32.cs | 33 +++-- 2 files changed, 29 insertions(+), 132 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs index 5190145276..40893914e1 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion ref Rgba32 sBase = ref this.source[0]; ref Argb32 dBase = ref this.dest[0]; - for (int i = 0; i < this.Count / 2; i += 2) + for (int i = 0; i < this.Count; i += 2) { ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); Rgba32 s1 = Unsafe.Add(ref s0, 1); @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion ref Rgba32 sBase = ref this.source[0]; ref Argb32 dBase = ref this.dest[0]; - for (int i = 0; i < this.Count / 4; i += 4) + for (int i = 0; i < this.Count; i += 4) { ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); @@ -98,119 +98,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion Unsafe.Add(ref d2, 1).FromRgba32(s3); } } - - [Benchmark] - public void Default_Group4_ManualInline_V1() - { - ref Rgba32 sBase = ref this.source[0]; - ref Argb32 dBase = ref this.dest[0]; - - for (int i = 0; i < this.Count / 4; i += 4) - { - ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); - ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); - ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); - Rgba32 s3 = Unsafe.Add(ref s2, 1); - - ref Argb32 d0 = ref Unsafe.Add(ref dBase, i); - ref Argb32 d1 = ref Unsafe.Add(ref d0, 1); - ref Argb32 d2 = ref Unsafe.Add(ref d1, 1); - ref Argb32 d3 = ref Unsafe.Add(ref d2, 1); - - d0.R = s0.R; - d0.G = s0.G; - d0.B = s0.B; - d0.A = s0.A; - - d1.R = s1.R; - d1.G = s1.G; - d1.B = s1.B; - d1.A = s1.A; - - d2.R = s2.R; - d2.G = s2.G; - d2.B = s2.B; - d2.A = s2.A; - - d3.R = s3.R; - d3.G = s3.G; - d3.B = s3.B; - d3.A = s3.A; - } - } - - [Benchmark] - public void Default_Group4_ManualInline_V2() - { - ref Rgba32 sBase = ref this.source[0]; - ref Argb32 dBase = ref this.dest[0]; - - for (int i = 0; i < this.Count / 4; i += 4) - { - ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); - ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); - ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); - Rgba32 s3 = Unsafe.Add(ref s2, 1); - - ref Argb32 d0 = ref Unsafe.Add(ref dBase, i); - ref Argb32 d1 = ref Unsafe.Add(ref d0, 1); - ref Argb32 d2 = ref Unsafe.Add(ref d1, 1); - ref Argb32 d3 = ref Unsafe.Add(ref d2, 1); - - d0.R = s0.R; - d1.R = s1.R; - d2.R = s2.R; - d3.R = s3.R; - - d0.G = s0.G; - d1.G = s1.G; - d2.G = s2.G; - d3.G = s3.G; - - d0.B = s0.B; - d1.B = s1.B; - d2.B = s2.B; - d3.B = s3.B; - - d0.A = s0.A; - d1.A = s1.A; - d2.A = s2.A; - d3.A = s3.A; - } - } - - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void Group4GenericImpl(ReadOnlySpan source, Span dest) - where TPixel : struct, IPixel - { - ref Rgba32 sBase = ref MemoryMarshal.GetReference(source); - ref TPixel dBase = ref MemoryMarshal.GetReference(dest); - - for (int i = 0; i < source.Length / 4; i += 4) - { - ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); - ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); - ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); - Rgba32 s3 = Unsafe.Add(ref s2, 1); - - ref TPixel d0 = ref Unsafe.Add(ref dBase, i); - ref TPixel d1 = ref Unsafe.Add(ref d0, 1); - ref TPixel d2 = ref Unsafe.Add(ref d1, 1); - - d0.FromRgba32(s0); - d1.FromRgba32(s1); - d2.FromRgba32(s2); - Unsafe.Add(ref d2, 1).FromRgba32(s3); - } - } - - [Benchmark] - public void Default_Group4_Generic() - { - Group4GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); - } - + [Benchmark] public void BitOps() { @@ -274,5 +162,15 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion return tmp1 + tmp3; } } + + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | + // -------------------- |------ |----------:|----------:|----------:|-------:| + // Default | 64 | 107.33 ns | 1.0633 ns | 0.9426 ns | 1.00 | + // Default_Generic | 64 | 111.15 ns | 0.3789 ns | 0.3544 ns | 1.04 | + // Default_Group2 | 64 | 90.36 ns | 0.7779 ns | 0.6896 ns | 0.84 | + // Default_Group4 | 64 | 82.39 ns | 0.2726 ns | 0.2550 ns | 0.77 | + // BitOps | 64 | 39.25 ns | 0.3266 ns | 0.2895 ns | 0.37 | + // BitOps_GroupAsULong | 64 | 41.80 ns | 0.2227 ns | 0.2083 ns | 0.39 | } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs index 9e638dbcc4..9cf16ea196 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs @@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion ref Rgba32 sBase = ref this.source[0]; ref Bgra32 dBase = ref this.dest[0]; - for (int i = 0; i < this.Count / 2; i+=2) + for (int i = 0; i < this.Count; i+=2) { ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); Rgba32 s1 = Unsafe.Add(ref s0, 1); @@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion ref Rgba32 sBase = ref this.source[0]; ref Bgra32 dBase = ref this.dest[0]; - for (int i = 0; i < this.Count / 4; i += 4) + for (int i = 0; i < this.Count; i += 4) { ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); @@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion Unsafe.Add(ref d2, 1).FromRgba32(s3); } } - + [MethodImpl(MethodImplOptions.NoInlining)] private static void Group4GenericImpl(ReadOnlySpan source, Span dest) where TPixel : struct, IPixel @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion ref Rgba32 sBase = ref MemoryMarshal.GetReference(source); ref TPixel dBase = ref MemoryMarshal.GetReference(dest); - for (int i = 0; i < source.Length / 4; i += 4) + for (int i = 0; i < source.Length; i += 4) { ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); @@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion } } - [Benchmark] + //[Benchmark] public void Default_Group4_Generic() { Group4GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); @@ -215,7 +215,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion } } - [Benchmark] + //[Benchmark] public void Bitops_SingleTuple() { ref Tuple4OfUInt32 sBase = ref Unsafe.As(ref this.source[0]); @@ -226,7 +226,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion } } - [Benchmark] + //[Benchmark] public void Bitops_Simd() { ref Octet.OfUInt32 sBase = ref Unsafe.As(ref this.source[0]); @@ -379,15 +379,14 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion // RESULTS: - // Method | Count | Mean | Error | StdDev | Scaled | - // ----------------------- |------ |----------:|----------:|----------:|-------:| - // Default | 64 | 107.13 ns | 0.7752 ns | 0.6872 ns | 1.00 | - // Default_Generic | 64 | 113.78 ns | 0.7713 ns | 0.6022 ns | 1.06 | - // Default_Group2 | 64 | 43.72 ns | 0.1711 ns | 0.1600 ns | 0.41 | - // Default_Group4 | 64 | 23.47 ns | 0.1901 ns | 0.1588 ns | 0.22 | - // Default_Group4_Generic | 64 | 32.46 ns | 0.4297 ns | 0.4019 ns | 0.30 | - // Bitops_Tuple | 64 | 77.71 ns | 0.2779 ns | 0.2599 ns | 0.73 | - // Bitops_SingleTuple | 64 | 58.64 ns | 0.4511 ns | 0.4220 ns | 0.55 | - // Bitops_Simd | 64 | 110.58 ns | 0.4686 ns | 0.4383 ns | 1.03 | + // Method | Count | Mean | Error | StdDev | Scaled | + // -------------------- |------ |----------:|----------:|----------:|-------:| + // Default | 64 | 106.84 ns | 0.4042 ns | 0.3583 ns | 1.00 | + // Default_Generic | 64 | 113.11 ns | 0.6998 ns | 0.6203 ns | 1.06 | + // Default_Group2 | 64 | 86.81 ns | 0.4976 ns | 0.4654 ns | 0.81 | + // Default_Group4 | 64 | 83.53 ns | 1.3826 ns | 1.2933 ns | 0.78 | + // BitOps | 64 | 54.23 ns | 0.1920 ns | 0.1796 ns | 0.51 | + // Bitops_Tuple | 64 | 73.45 ns | 0.5475 ns | 0.4853 ns | 0.69 | + // BitOps_GroupAsULong | 64 | 64.28 ns | 0.4046 ns | 0.3785 ns | 0.60 | } } \ No newline at end of file From e70e7d4ab7b06fab386084c9878c72d4f85b3561 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 25 Oct 2018 02:04:55 +0200 Subject: [PATCH 230/381] Optimized bulk conversion for common pixel types --- .../Argb32.PixelOperations.Generated.cs | 117 ++++++++++++++---- .../Bgr24.PixelOperations.Generated.cs | 37 ++++++ .../Bgra32.PixelOperations.Generated.cs | 111 +++++++++++++---- .../Gray16.PixelOperations.Generated.cs | 12 ++ .../Gray8.PixelOperations.Generated.cs | 12 ++ .../Rgb24.PixelOperations.Generated.cs | 37 ++++++ .../Rgb48.PixelOperations.Generated.cs | 12 ++ .../Rgba32.PixelOperations.Generated.cs | 76 +++++++++--- .../Rgba64.PixelOperations.Generated.cs | 12 ++ .../Generated/_Common.ttinclude | 100 ++++++++++++++- .../Rgba32.PixelOperations.cs | 20 +-- .../RgbaVector.PixelOperations.cs | 8 +- .../PixelFormats/PixelOperations{TPixel}.cs | 82 ++++++++++-- 13 files changed, 537 insertions(+), 99 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs index 09f10716e2..e6b8922e9d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs @@ -4,6 +4,8 @@ // using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -24,6 +26,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromArgb32(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -32,109 +35,167 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - + /// - internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + } + + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + } + + /// + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); for (int i = 0; i < sourcePixels.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromArgb32(sp); + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToRgba32(sp); } } - + /// - internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + internal override void FromRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToArgb32(sp); + } + } + /// + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); for (int i = 0; i < sourcePixels.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToBgra32(sp); + } + } - dp.FromArgb32(sp); + /// + internal override void FromBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToArgb32(sp); } } /// - internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); dp.FromArgb32(sp); } } /// - internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); dp.FromArgb32(sp); } } /// - internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); dp.FromArgb32(sp); } } /// - internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); dp.FromArgb32(sp); } @@ -143,6 +204,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -160,6 +222,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs index f8c61e4fac..9b1740013d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs @@ -4,6 +4,8 @@ // using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -24,6 +26,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromBgr24(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -32,15 +35,42 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } + + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + } + + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + } + /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -58,6 +88,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -75,6 +106,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -92,6 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -109,6 +142,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -126,6 +160,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -143,6 +178,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -160,6 +196,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs index 9bddd18e9c..37d6b72d71 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs @@ -4,6 +4,8 @@ // using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -24,6 +26,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromBgra32(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -32,32 +35,104 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - + + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + } + /// - internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + } + + /// + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); for (int i = 0; i < sourcePixels.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToRgba32(sp); + } + } - dp.FromBgra32(sp); + /// + internal override void FromRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToBgra32(sp); + } + } + /// + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToArgb32(sp); + } + } + + /// + internal override void FromArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToBgra32(sp); } } /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -75,6 +150,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -92,6 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -109,6 +186,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -119,23 +197,6 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - dp.FromBgra32(sp); - } - } - - /// - internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) - { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - - for (int i = 0; i < sourcePixels.Length; i++) - { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.FromBgra32(sp); } } @@ -143,6 +204,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -160,6 +222,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs index 31c5755345..638db1d0d8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs @@ -4,6 +4,8 @@ // using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -24,6 +26,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromGray16(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -32,6 +35,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); @@ -41,6 +45,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -58,6 +63,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -75,6 +81,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -92,6 +99,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -109,6 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -126,6 +135,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -143,6 +153,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -160,6 +171,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs index 14a2c858cf..6bf0693c2c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs @@ -4,6 +4,8 @@ // using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -24,6 +26,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromGray8(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -32,6 +35,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); @@ -41,6 +45,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -58,6 +63,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -75,6 +81,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -92,6 +99,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -109,6 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -126,6 +135,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -143,6 +153,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -160,6 +171,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs index f8b80020ec..6ff87eb385 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs @@ -4,6 +4,8 @@ // using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -24,6 +26,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromRgb24(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -32,15 +35,42 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } + + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + } + + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + } + /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -58,6 +88,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -75,6 +106,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -92,6 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -109,6 +142,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -126,6 +160,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -143,6 +178,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -160,6 +196,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs index 5741b10706..9b4584d767 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs @@ -4,6 +4,8 @@ // using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -24,6 +26,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromRgb48(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -32,6 +35,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); @@ -41,6 +45,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -58,6 +63,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -75,6 +81,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -92,6 +99,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -109,6 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -126,6 +135,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -143,6 +153,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -160,6 +171,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs index 9f7b624c07..8e15ca1f4d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs @@ -4,6 +4,8 @@ // using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -24,6 +26,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromRgba32(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -32,58 +35,88 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - - /// - internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + /// + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); for (int i = 0; i < sourcePixels.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba32(sp); + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToArgb32(sp); } } - + /// - internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + internal override void FromArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToRgba32(sp); + } + } + /// + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); for (int i = 0; i < sourcePixels.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToBgra32(sp); + } + } - dp.FromRgba32(sp); + /// + internal override void FromBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToRgba32(sp); } } /// - internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgba32(sp); } @@ -92,6 +125,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -109,6 +143,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -126,6 +161,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -143,6 +179,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -160,6 +197,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs index 411178b825..caaba78094 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs @@ -4,6 +4,8 @@ // using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -24,6 +26,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromRgba64(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -32,6 +35,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); @@ -41,6 +45,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -58,6 +63,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -75,6 +81,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -92,6 +99,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -109,6 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -126,6 +135,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -143,6 +153,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -160,6 +171,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude index bc23edb015..4501f4972e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude @@ -9,10 +9,17 @@ // using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; <#+ - static readonly string[] CommonPixelTypeNames = { "Argb32", "Bgr24", "Bgra32", "Gray8", "Gray16", "Rgb24", "Rgba32", "Rgb48", "Rgba64" }; + static readonly string[] CommonPixelTypes = { "Argb32", "Bgr24", "Bgra32", "Gray8", "Gray16", "Rgb24", "Rgba32", "Rgb48", "Rgba64" }; + + static readonly string[] Optimized32BitTypes = { "Rgba32", "Argb32", "Bgra32" }; + + // Types with Rgba32-combatible to/from Vector4 conversion + static readonly string[] Rgba32CompatibleTypes = { "Argb32", "Bgra32", "Rgb24", "Bgr24" }; void GenerateDefaultSelfConversionMethods(string pixelType) { @@ -21,6 +28,7 @@ using System.Runtime.InteropServices; /// internal override void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -29,6 +37,7 @@ using System.Runtime.InteropServices; /// internal override void To<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<<#=pixelType#>> destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); @@ -44,6 +53,7 @@ using System.Runtime.InteropServices; /// internal override void To<#=toPixelType#>(Configuration configuration, ReadOnlySpan<<#=fromPixelType#>> sourcePixels, Span<<#=toPixelType#>> destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref <#=fromPixelType#> sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -60,13 +70,97 @@ using System.Runtime.InteropServices; <#+ } + void GenerateOptimized32BitConversionMethods(string thisPixelType, string otherPixelType) + { + #> + /// + internal override void To<#=otherPixelType#>(Configuration configuration, ReadOnlySpan<<#=thisPixelType#>> sourcePixels, Span<<#=otherPixelType#>> destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As<<#=thisPixelType#>,uint>(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As<<#=otherPixelType#>, uint>(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.From<#=thisPixelType#>.To<#=otherPixelType#>(sp); + } + } + + /// + internal override void From<#=otherPixelType#>(Configuration configuration, ReadOnlySpan<<#=otherPixelType#>> sourcePixels, Span<<#=thisPixelType#>> destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As<<#=otherPixelType#>,uint>(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As<<#=thisPixelType#>, uint>(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.From<#=otherPixelType#>.To<#=thisPixelType#>(sp); + } + } + <#+ + } + + void GenerateRgba32CompatibleVector4ConversionMethods(string pixelType) + { + #> + + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span<<#=pixelType#>> destPixels) + { + this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) + { + this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span<<#=pixelType#>> destPixels) + { + this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + } + + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) + { + this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + } + + <#+ + } + void GenerateAllDefaultConversionMethods(string pixelType) { GenerateDefaultSelfConversionMethods(pixelType); - var allOtherPixelTypes = CommonPixelTypeNames.Where(p => p != pixelType); + if (Rgba32CompatibleTypes.Contains(pixelType)) + { + GenerateRgba32CompatibleVector4ConversionMethods(pixelType); + } + + var matching32BitTypes = Optimized32BitTypes.Contains(pixelType) ? + Optimized32BitTypes.Where(p => p != pixelType) : + Enumerable.Empty(); + + foreach (string destPixelType in matching32BitTypes) + { + GenerateOptimized32BitConversionMethods(pixelType, destPixelType); + } + + var otherCommonNon32Types = CommonPixelTypes + .Where(p => p != pixelType) + .Except(matching32BitTypes); - foreach (string destPixelType in allOtherPixelTypes) + foreach (string destPixelType in otherCommonNon32Types) { GenerateDefaultConvertToMethod(pixelType, destPixelType); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs index 0f5ddf3729..004b25cd33 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs @@ -21,31 +21,31 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToVector4( Configuration configuration, - ReadOnlySpan sourceColors, - Span destinationVectors) + ReadOnlySpan sourcePixels, + Span destVectors) { - Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); - destinationVectors = destinationVectors.Slice(0, sourceColors.Length); + destVectors = destVectors.Slice(0, sourcePixels.Length); SimdUtils.BulkConvertByteToNormalizedFloat( - MemoryMarshal.Cast(sourceColors), - MemoryMarshal.Cast(destinationVectors)); + MemoryMarshal.Cast(sourcePixels), + MemoryMarshal.Cast(destVectors)); } /// internal override void FromVector4( Configuration configuration, ReadOnlySpan sourceVectors, - Span destinationColors) + Span destPixels) { - Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); - destinationColors = destinationColors.Slice(0, sourceVectors.Length); + destPixels = destPixels.Slice(0, sourceVectors.Length); SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( MemoryMarshal.Cast(sourceVectors), - MemoryMarshal.Cast(destinationColors)); + MemoryMarshal.Cast(destPixels)); } /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs index cb12d944c7..bffaf57ddd 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs @@ -38,12 +38,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToVector4( Configuration configuration, - ReadOnlySpan sourceColors, - Span destinationVectors) + ReadOnlySpan sourcePixels, + Span destVectors) { - Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); - MemoryMarshal.Cast(sourceColors).CopyTo(destinationVectors); + MemoryMarshal.Cast(sourcePixels).CopyTo(destVectors); } } } diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index ad5aee8c7c..3cebf7b54a 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -26,17 +27,17 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// A to configure internal operations /// The to the source vectors. - /// The to the destination colors. + /// The to the destination colors. internal virtual void FromVector4( Configuration configuration, ReadOnlySpan sourceVectors, - Span destinationColors) + Span destPixels) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); - ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); + ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < sourceVectors.Length; i++) { @@ -50,20 +51,20 @@ namespace SixLabors.ImageSharp.PixelFormats /// Bulk version of converting 'sourceColors.Length' pixels into 'destinationVectors'. /// /// A to configure internal operations - /// The to the source colors. - /// The to the destination vectors. + /// The to the source colors. + /// The to the destination vectors. internal virtual void ToVector4( Configuration configuration, - ReadOnlySpan sourceColors, - Span destinationVectors) + ReadOnlySpan sourcePixels, + Span destVectors) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); - ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); - ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); + ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Vector4 destRef = ref MemoryMarshal.GetReference(destVectors); - for (int i = 0; i < sourceColors.Length; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); ref Vector4 dp = ref Unsafe.Add(ref destRef, i); @@ -178,5 +179,62 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromScaledVector4(sp.ToScaledVector4()); } } + + /// + /// Provides an efficient default implementation for and + /// which is applicable for -compatible pixel types where + /// returns the same scaled result as . + /// The method is works by internally converting to a therefore it's not applicable for that type! + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal void RunRgba32CompatibleToVector4Conversion( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destVectors) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); + + int count = sourcePixels.Length; + + using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count)) + { + Span tempSpan = tempBuffer.Memory.Span; + this.ToRgba32(configuration, sourcePixels, tempSpan); + + SimdUtils.BulkConvertByteToNormalizedFloat( + MemoryMarshal.Cast(tempSpan), + MemoryMarshal.Cast(destVectors)); + } + } + + /// + /// Provides an efficient default implementation for and + /// which is applicable for -compatible pixel types where + /// returns the same scaled result as . + /// The method is works by internally converting to a therefore it's not applicable for that type! + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal void RunRgba32CompatibleFromVector4Conversion( + Configuration configuration, + ReadOnlySpan sourceVectors, + Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); + + int count = sourceVectors.Length; + + using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count)) + { + Span tempSpan = tempBuffer.Memory.Span; + + SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( + MemoryMarshal.Cast(sourceVectors), + MemoryMarshal.Cast(tempSpan)); + + this.FromRgba32(configuration, tempSpan, destPixels); + } + } } } \ No newline at end of file From 0fc01d75f454babd74b295cd329df817a32b4b1e Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 25 Oct 2018 02:43:02 +0200 Subject: [PATCH 231/381] run default implementation for small buffers --- .../PixelFormats/PixelOperations{TPixel}.cs | 63 +++++++++++++------ .../Color/Bulk/ToVector4.cs | 28 ++++++--- 2 files changed, 66 insertions(+), 25 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 3cebf7b54a..c3d8e23b91 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -36,15 +36,7 @@ namespace SixLabors.ImageSharp.PixelFormats Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); - ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - for (int i = 0; i < sourceVectors.Length; i++) - { - ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - dp.FromVector4(sp); - } + FromVector4DefaultImpl(sourceVectors, destPixels); } /// @@ -61,15 +53,7 @@ namespace SixLabors.ImageSharp.PixelFormats Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); - ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Vector4 destRef = ref MemoryMarshal.GetReference(destVectors); - - for (int i = 0; i < sourcePixels.Length; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); - ref Vector4 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToVector4(); - } + ToVector4DefaultImpl(sourcePixels, destVectors); } /// @@ -135,6 +119,7 @@ namespace SixLabors.ImageSharp.PixelFormats Span destinationColors) where TDestinationPixel : struct, IPixel { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceColors, destinationColors, nameof(destinationColors)); int count = sourceColors.Length; @@ -197,6 +182,13 @@ namespace SixLabors.ImageSharp.PixelFormats int count = sourcePixels.Length; + // Not worth for small buffers: + if (count < 128) + { + ToVector4DefaultImpl(sourcePixels, destVectors); + return; + } + using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count)) { Span tempSpan = tempBuffer.Memory.Span; @@ -225,6 +217,13 @@ namespace SixLabors.ImageSharp.PixelFormats int count = sourceVectors.Length; + // Not worth for small buffers: + if (count < 128) + { + FromVector4DefaultImpl(sourceVectors, destPixels); + return; + } + using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count)) { Span tempSpan = tempBuffer.Memory.Span; @@ -236,5 +235,33 @@ namespace SixLabors.ImageSharp.PixelFormats this.FromRgba32(configuration, tempSpan, destPixels); } } + + [MethodImpl(InliningOptions.ShortMethod)] + private static void FromVector4DefaultImpl(ReadOnlySpan sourceVectors, Span destPixels) + { + ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); + ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourceVectors.Length; i++) + { + ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + dp.FromVector4(sp); + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + private static void ToVector4DefaultImpl(ReadOnlySpan sourcePixels, Span destVectors) + { + ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Vector4 destRef = ref MemoryMarshal.GetReference(destVectors); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref Vector4 dp = ref Unsafe.Add(ref destRef, i); + dp = sp.ToVector4(); + } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index f0fee649af..897badd9f2 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Params( 64, - //256, + 256, //512, //1024, 2048)] @@ -58,20 +58,25 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk d[i] = s[i].ToVector4(); } } + [Benchmark] - public void PixelOperations_Base() + public void PixelOperations_Specialized() { - new PixelOperations().ToVector4( + PixelOperations.Instance.ToVector4( this.Configuration, this.source.GetSpan(), this.destination.GetSpan()); } + } - [Benchmark] - public void PixelOperations_Specialized() + [Config(typeof(Config.ShortClr))] + public class ToVector4_Bgra32 : ToVector4 + { + [Benchmark(Baseline = true)] + public void PixelOperations_Base() { - PixelOperations.Instance.ToVector4( + new PixelOperations().ToVector4( this.Configuration, this.source.GetSpan(), this.destination.GetSpan()); @@ -89,7 +94,16 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk SimdUtils.FallbackIntrinsics128.BulkConvertByteToNormalizedFloat(sBytes, dFloats); } - + + [Benchmark] + public void PixelOperations_Base() + { + new PixelOperations().ToVector4( + this.Configuration, + this.source.GetSpan(), + this.destination.GetSpan()); + } + [Benchmark(Baseline = true)] public void BasicIntrinsics256() { From d154c45007cc56cc44f29deabcdcc2de0eb44749 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 26 Oct 2018 14:30:11 +0200 Subject: [PATCH 232/381] fix Gray8.ToString() --- src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs index d23fda7991..4ed5904c2b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs @@ -140,7 +140,7 @@ namespace SixLabors.ImageSharp.PixelFormats public bool Equals(Gray8 other) => this.PackedValue.Equals(other.PackedValue); /// - public override string ToString() => $"Gray8({this.PackedValue}"; + public override string ToString() => $"Gray8({this.PackedValue})"; /// [MethodImpl(InliningOptions.ShortMethod)] From b87c93e1951fa2b63be8c394b645fa68eb422d6e Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 26 Oct 2018 15:18:26 +0200 Subject: [PATCH 233/381] benchmakrs --- .../Color/Bulk/FromRgba32Bytes.cs | 28 ++- .../Color/Bulk/{ToXyz.cs => Rgb24Bytes.cs} | 4 +- .../Bulk/{ToXyzw.cs => ToRgba32Bytes.cs} | 16 +- .../Color/Bulk/ToVector4.cs | 169 +----------------- .../Color/Bulk/ToVector4_Bgra32.cs | 20 +++ .../Color/Bulk/ToVector4_Rgba32.cs | 164 +++++++++++++++++ .../PixelConversion_Rgba32_To_Bgra32.cs | 24 +-- 7 files changed, 232 insertions(+), 193 deletions(-) rename tests/ImageSharp.Benchmarks/Color/Bulk/{ToXyz.cs => Rgb24Bytes.cs} (94%) rename tests/ImageSharp.Benchmarks/Color/Bulk/{ToXyzw.cs => ToRgba32Bytes.cs} (87%) create mode 100644 tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs create mode 100644 tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs index 32565c23dc..b964221764 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs @@ -22,7 +22,10 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk private Configuration configuration; - [Params(16, 128, 1024)] + [Params( + 128, + 1024, + 2048)] public int Count { get; set; } [GlobalSetup] @@ -40,8 +43,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.source.Dispose(); } - [Benchmark(Baseline = true)] - public void PerElement() + //[Benchmark] + public void Naive() { Span s = this.source.GetSpan(); Span d = this.destination.GetSpan(); @@ -55,7 +58,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - [Benchmark] + [Benchmark(Baseline = true)] public void CommonBulk() { new PixelOperations().FromRgba32Bytes(this.configuration, this.source.GetSpan(), this.destination.GetSpan(), this.Count); @@ -68,7 +71,22 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - public class FromRgba32BytesRgba32 : FromRgba32Bytes + public class FromRgba32Bytes_ToRgba32 : FromRgba32Bytes + { + } + + public class FromRgba32Bytes_ToBgra32 : FromRgba32Bytes { + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | + // -------------- |------ |-----------:|----------:|----------:|-------:| + // CommonBulk | 128 | 207.1 ns | 3.723 ns | 3.300 ns | 1.00 | + // OptimizedBulk | 128 | 166.5 ns | 1.204 ns | 1.005 ns | 0.80 | + // | | | | | | + // CommonBulk | 1024 | 1,333.9 ns | 12.426 ns | 11.624 ns | 1.00 | + // OptimizedBulk | 1024 | 974.1 ns | 18.803 ns | 16.669 ns | 0.73 | + // | | | | | | + // CommonBulk | 2048 | 2,625.4 ns | 30.143 ns | 26.721 ns | 1.00 | + // OptimizedBulk | 2048 | 1,843.0 ns | 20.505 ns | 18.177 ns | 0.70 | } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/Rgb24Bytes.cs similarity index 94% rename from tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs rename to tests/ImageSharp.Benchmarks/Color/Bulk/Rgb24Bytes.cs index 912c3e4b2e..294baa9d51 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/Rgb24Bytes.cs @@ -10,7 +10,7 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk { - public abstract class ToXyz + public abstract class Rgb24Bytes where TPixel : struct, IPixel { private IMemoryOwner source; @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.Count); } - public class ToXyz_Rgba32 : ToXyz + public class Rgb24Bytes_Rgba32 : Rgb24Bytes { } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToRgba32Bytes.cs similarity index 87% rename from tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs rename to tests/ImageSharp.Benchmarks/Color/Bulk/ToRgba32Bytes.cs index 37694f64cd..7f4b2bc41d 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToRgba32Bytes.cs @@ -12,7 +12,7 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk { - public abstract class ToXyzw + public abstract class ToRgba32Bytes where TPixel : struct, IPixel { private IMemoryOwner source; @@ -39,8 +39,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.destination.Dispose(); } - [Benchmark(Baseline = true)] - public void PerElement() + //[Benchmark] + public void Naive() { Span s = this.source.GetSpan(); Span d = this.destination.GetSpan(); @@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - [Benchmark] + [Benchmark(Baseline = true)] public void CommonBulk() => new PixelOperations().ToRgba32Bytes( this.configuration, @@ -75,11 +75,15 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.Count); } - public class ToXyzw_Rgba32 : ToXyzw + public class ToRgba32Bytes_FromRgba32 : ToRgba32Bytes + { + } + + public class ToRgba32Bytes_FromArgb32 : ToRgba32Bytes { } - public class ToXyzw_Argb32 : ToXyzw + public class ToRgba32Bytes_FromBgra32 : ToRgba32Bytes { } } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 897badd9f2..70de8f4e27 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -6,8 +6,6 @@ using System.Buffers; using System; using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; @@ -48,7 +46,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } //[Benchmark] - public void PerElement() + public void Naive() { Span s = this.source.GetSpan(); Span d = this.destination.GetSpan(); @@ -69,169 +67,4 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.destination.GetSpan()); } } - - [Config(typeof(Config.ShortClr))] - public class ToVector4_Bgra32 : ToVector4 - { - [Benchmark(Baseline = true)] - public void PixelOperations_Base() - { - new PixelOperations().ToVector4( - this.Configuration, - this.source.GetSpan(), - this.destination.GetSpan()); - } - } - - [Config(typeof(Config.ShortClr))] - public class ToVector4_Rgba32 : ToVector4 - { - [Benchmark] - public void FallbackIntrinsics128() - { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - - SimdUtils.FallbackIntrinsics128.BulkConvertByteToNormalizedFloat(sBytes, dFloats); - } - - [Benchmark] - public void PixelOperations_Base() - { - new PixelOperations().ToVector4( - this.Configuration, - this.source.GetSpan(), - this.destination.GetSpan()); - } - - [Benchmark(Baseline = true)] - public void BasicIntrinsics256() - { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - - SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(sBytes, dFloats); - } - - [Benchmark] - public void ExtendedIntrinsics() - { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - - SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats); - } - - //[Benchmark] - public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops() - { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - - int n = dFloats.Length / Vector.Count; - - ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); - ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dFloats)); - ref Vector destBaseU = ref Unsafe.As, Vector>(ref destBase); - - for (int i = 0; i < n; i++) - { - Vector b = Unsafe.Add(ref sourceBase, i); - - Vector.Widen(b, out Vector s0, out Vector s1); - Vector.Widen(s0, out Vector w0, out Vector w1); - Vector.Widen(s1, out Vector w2, out Vector w3); - - ref Vector d = ref Unsafe.Add(ref destBaseU, i * 4); - d = w0; - Unsafe.Add(ref d, 1) = w1; - Unsafe.Add(ref d, 2) = w2; - Unsafe.Add(ref d, 3) = w3; - } - - n = dFloats.Length / Vector.Count; - var scale = new Vector(1f / 255f); - - for (int i = 0; i < n; i++) - { - ref Vector dRef = ref Unsafe.Add(ref destBase, i); - - Vector du = Vector.AsVectorInt32(dRef); - Vector v = Vector.ConvertToSingle(du); - v *= scale; - - dRef = v; - } - } - - //[Benchmark] - public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_ConvertInSameLoop() - { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - - int n = dFloats.Length / Vector.Count; - - ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); - ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dFloats)); - var scale = new Vector(1f / 255f); - - for (int i = 0; i < n; i++) - { - Vector b = Unsafe.Add(ref sourceBase, i); - - Vector.Widen(b, out Vector s0, out Vector s1); - Vector.Widen(s0, out Vector w0, out Vector w1); - Vector.Widen(s1, out Vector w2, out Vector w3); - - Vector f0 = ConvertToNormalizedSingle(w0, scale); - Vector f1 = ConvertToNormalizedSingle(w1, scale); - Vector f2 = ConvertToNormalizedSingle(w2, scale); - Vector f3 = ConvertToNormalizedSingle(w3, scale); - - ref Vector d = ref Unsafe.Add(ref destBase, i * 4); - d = f0; - Unsafe.Add(ref d, 1) = f1; - Unsafe.Add(ref d, 2) = f2; - Unsafe.Add(ref d, 3) = f3; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector ConvertToNormalizedSingle(Vector u, Vector scale) - { - Vector vi = Vector.AsVectorInt32(u); - Vector v = Vector.ConvertToSingle(vi); - v *= scale; - return v; - } - - // RESULTS (2018 October): - // - // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | - // ---------------------------- |-------- |------ |------------:|-------------:|------------:|-------:|---------:|-------:|----------:| - // FallbackIntrinsics128 | Clr | 64 | 287.62 ns | 6.026 ns | 0.3405 ns | 1.19 | 0.00 | - | 0 B | - // BasicIntrinsics256 | Clr | 64 | 240.83 ns | 10.585 ns | 0.5981 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsics | Clr | 64 | 168.28 ns | 11.478 ns | 0.6485 ns | 0.70 | 0.00 | - | 0 B | - // PixelOperations_Base | Clr | 64 | 334.08 ns | 38.048 ns | 2.1498 ns | 1.39 | 0.01 | 0.0072 | 24 B | - // PixelOperations_Specialized | Clr | 64 | 255.41 ns | 10.939 ns | 0.6181 ns | 1.06 | 0.00 | - | 0 B | <--- ceremonial overhead has been minimized! - // | | | | | | | | | | - // FallbackIntrinsics128 | Core | 64 | 183.29 ns | 8.931 ns | 0.5046 ns | 1.32 | 0.00 | - | 0 B | - // BasicIntrinsics256 | Core | 64 | 139.18 ns | 7.633 ns | 0.4313 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsics | Core | 64 | 66.29 ns | 16.366 ns | 0.9247 ns | 0.48 | 0.01 | - | 0 B | - // PixelOperations_Base | Core | 64 | 257.75 ns | 16.959 ns | 0.9582 ns | 1.85 | 0.01 | 0.0072 | 24 B | - // PixelOperations_Specialized | Core | 64 | 90.14 ns | 9.955 ns | 0.5625 ns | 0.65 | 0.00 | - | 0 B | - // | | | | | | | | | | - // FallbackIntrinsics128 | Clr | 2048 | 5,011.84 ns | 347.991 ns | 19.6621 ns | 1.22 | 0.01 | - | 0 B | - // BasicIntrinsics256 | Clr | 2048 | 4,119.35 ns | 720.153 ns | 40.6900 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsics | Clr | 2048 | 1,195.29 ns | 164.389 ns | 9.2883 ns |!! 0.29 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! - // PixelOperations_Base | Clr | 2048 | 6,820.58 ns | 823.433 ns | 46.5255 ns | 1.66 | 0.02 | - | 24 B | - // PixelOperations_Specialized | Clr | 2048 | 4,203.53 ns | 176.714 ns | 9.9847 ns | 1.02 | 0.01 | - | 0 B | <--- can't yet detect whether ExtendedIntrinsics are available :( - // | | | | | | | | | | - // FallbackIntrinsics128 | Core | 2048 | 5,017.89 ns | 4,021.533 ns | 227.2241 ns | 1.24 | 0.05 | - | 0 B | - // BasicIntrinsics256 | Core | 2048 | 4,046.51 ns | 1,150.390 ns | 64.9992 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsics | Core | 2048 | 1,130.59 ns | 832.588 ns | 47.0427 ns |!! 0.28 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock! - // PixelOperations_Base | Core | 2048 | 6,752.68 ns | 272.820 ns | 15.4148 ns | 1.67 | 0.02 | - | 24 B | - // PixelOperations_Specialized | Core | 2048 | 1,126.13 ns | 79.192 ns | 4.4745 ns |!! 0.28 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! - } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs new file mode 100644 index 0000000000..028bfe46f8 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs @@ -0,0 +1,20 @@ +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk +{ + [Config(typeof(Config.ShortClr))] + public class ToVector4_Bgra32 : ToVector4 + { + [Benchmark(Baseline = true)] + public void PixelOperations_Base() + { + new PixelOperations().ToVector4( + this.Configuration, + this.source.GetSpan(), + this.destination.GetSpan()); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs new file mode 100644 index 0000000000..ab05a14073 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs @@ -0,0 +1,164 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk +{ + [Config(typeof(Config.ShortClr))] + public class ToVector4_Rgba32 : ToVector4 + { + [Benchmark] + public void FallbackIntrinsics128() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.FallbackIntrinsics128.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + } + + [Benchmark] + public void PixelOperations_Base() + { + new PixelOperations().ToVector4( + this.Configuration, + this.source.GetSpan(), + this.destination.GetSpan()); + } + + [Benchmark(Baseline = true)] + public void BasicIntrinsics256() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + } + + [Benchmark] + public void ExtendedIntrinsics() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + } + + //[Benchmark] + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + int n = dFloats.Length / Vector.Count; + + ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dFloats)); + ref Vector destBaseU = ref Unsafe.As, Vector>(ref destBase); + + for (int i = 0; i < n; i++) + { + Vector b = Unsafe.Add(ref sourceBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + ref Vector d = ref Unsafe.Add(ref destBaseU, i * 4); + d = w0; + Unsafe.Add(ref d, 1) = w1; + Unsafe.Add(ref d, 2) = w2; + Unsafe.Add(ref d, 3) = w3; + } + + n = dFloats.Length / Vector.Count; + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + ref Vector dRef = ref Unsafe.Add(ref destBase, i); + + Vector du = Vector.AsVectorInt32(dRef); + Vector v = Vector.ConvertToSingle(du); + v *= scale; + + dRef = v; + } + } + + //[Benchmark] + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_ConvertInSameLoop() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + int n = dFloats.Length / Vector.Count; + + ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dFloats)); + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + Vector b = Unsafe.Add(ref sourceBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + Vector f0 = ConvertToNormalizedSingle(w0, scale); + Vector f1 = ConvertToNormalizedSingle(w1, scale); + Vector f2 = ConvertToNormalizedSingle(w2, scale); + Vector f3 = ConvertToNormalizedSingle(w3, scale); + + ref Vector d = ref Unsafe.Add(ref destBase, i * 4); + d = f0; + Unsafe.Add(ref d, 1) = f1; + Unsafe.Add(ref d, 2) = f2; + Unsafe.Add(ref d, 3) = f3; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector ConvertToNormalizedSingle(Vector u, Vector scale) + { + Vector vi = Vector.AsVectorInt32(u); + Vector v = Vector.ConvertToSingle(vi); + v *= scale; + return v; + } + + // RESULTS (2018 October): + // + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ---------------------------- |-------- |------ |------------:|-------------:|------------:|-------:|---------:|-------:|----------:| + // FallbackIntrinsics128 | Clr | 64 | 287.62 ns | 6.026 ns | 0.3405 ns | 1.19 | 0.00 | - | 0 B | + // BasicIntrinsics256 | Clr | 64 | 240.83 ns | 10.585 ns | 0.5981 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Clr | 64 | 168.28 ns | 11.478 ns | 0.6485 ns | 0.70 | 0.00 | - | 0 B | + // PixelOperations_Base | Clr | 64 | 334.08 ns | 38.048 ns | 2.1498 ns | 1.39 | 0.01 | 0.0072 | 24 B | + // PixelOperations_Specialized | Clr | 64 | 255.41 ns | 10.939 ns | 0.6181 ns | 1.06 | 0.00 | - | 0 B | <--- ceremonial overhead has been minimized! + // | | | | | | | | | | + // FallbackIntrinsics128 | Core | 64 | 183.29 ns | 8.931 ns | 0.5046 ns | 1.32 | 0.00 | - | 0 B | + // BasicIntrinsics256 | Core | 64 | 139.18 ns | 7.633 ns | 0.4313 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Core | 64 | 66.29 ns | 16.366 ns | 0.9247 ns | 0.48 | 0.01 | - | 0 B | + // PixelOperations_Base | Core | 64 | 257.75 ns | 16.959 ns | 0.9582 ns | 1.85 | 0.01 | 0.0072 | 24 B | + // PixelOperations_Specialized | Core | 64 | 90.14 ns | 9.955 ns | 0.5625 ns | 0.65 | 0.00 | - | 0 B | + // | | | | | | | | | | + // FallbackIntrinsics128 | Clr | 2048 | 5,011.84 ns | 347.991 ns | 19.6621 ns | 1.22 | 0.01 | - | 0 B | + // BasicIntrinsics256 | Clr | 2048 | 4,119.35 ns | 720.153 ns | 40.6900 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Clr | 2048 | 1,195.29 ns | 164.389 ns | 9.2883 ns |!! 0.29 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! + // PixelOperations_Base | Clr | 2048 | 6,820.58 ns | 823.433 ns | 46.5255 ns | 1.66 | 0.02 | - | 24 B | + // PixelOperations_Specialized | Clr | 2048 | 4,203.53 ns | 176.714 ns | 9.9847 ns | 1.02 | 0.01 | - | 0 B | <--- can't yet detect whether ExtendedIntrinsics are available :( + // | | | | | | | | | | + // FallbackIntrinsics128 | Core | 2048 | 5,017.89 ns | 4,021.533 ns | 227.2241 ns | 1.24 | 0.05 | - | 0 B | + // BasicIntrinsics256 | Core | 2048 | 4,046.51 ns | 1,150.390 ns | 64.9992 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Core | 2048 | 1,130.59 ns | 832.588 ns | 47.0427 ns |!! 0.28 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock! + // PixelOperations_Base | Core | 2048 | 6,752.68 ns | 272.820 ns | 15.4148 ns | 1.67 | 0.02 | - | 24 B | + // PixelOperations_Specialized | Core | 2048 | 1,126.13 ns | 79.192 ns | 4.4745 ns |!! 0.28 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs index 9cf16ea196..a8fea68661 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs @@ -12,7 +12,7 @@ using SixLabors.ImageSharp.Tuples; namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion { //[MonoJob] - [RyuJitX64Job] + //[RyuJitX64Job] public class PixelConversion_Rgba32_To_Bgra32 { private Rgba32[] source; @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion for (int i = 0; i < this.Count; i++) { - Rgba32 s = Unsafe.Add(ref sBase, i); + ref Rgba32 s = ref Unsafe.Add(ref sBase, i); Unsafe.Add(ref dBase, i).FromRgba32(s); } } @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion for (int i = 0; i < source.Length; i++) { - Rgba32 s = Unsafe.Add(ref sBase, i); + ref Rgba32 s = ref Unsafe.Add(ref sBase, i); Unsafe.Add(ref dBase, i).FromRgba32(s); } } @@ -379,14 +379,14 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion // RESULTS: - // Method | Count | Mean | Error | StdDev | Scaled | - // -------------------- |------ |----------:|----------:|----------:|-------:| - // Default | 64 | 106.84 ns | 0.4042 ns | 0.3583 ns | 1.00 | - // Default_Generic | 64 | 113.11 ns | 0.6998 ns | 0.6203 ns | 1.06 | - // Default_Group2 | 64 | 86.81 ns | 0.4976 ns | 0.4654 ns | 0.81 | - // Default_Group4 | 64 | 83.53 ns | 1.3826 ns | 1.2933 ns | 0.78 | - // BitOps | 64 | 54.23 ns | 0.1920 ns | 0.1796 ns | 0.51 | - // Bitops_Tuple | 64 | 73.45 ns | 0.5475 ns | 0.4853 ns | 0.69 | - // BitOps_GroupAsULong | 64 | 64.28 ns | 0.4046 ns | 0.3785 ns | 0.60 | + // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | + // -------------------- |------ |---------:|----------:|----------:|-------:|---------:| + // Default | 64 | 82.67 ns | 0.6737 ns | 0.5625 ns | 1.00 | 0.00 | + // Default_Generic | 64 | 88.73 ns | 1.7959 ns | 1.7638 ns | 1.07 | 0.02 | + // Default_Group2 | 64 | 91.03 ns | 1.5237 ns | 1.3508 ns | 1.10 | 0.02 | + // Default_Group4 | 64 | 86.62 ns | 1.5737 ns | 1.4720 ns | 1.05 | 0.02 | + // BitOps | 64 | 57.45 ns | 0.6067 ns | 0.5066 ns | 0.69 | 0.01 | + // Bitops_Tuple | 64 | 75.47 ns | 1.1824 ns | 1.1060 ns | 0.91 | 0.01 | + // BitOps_GroupAsULong | 64 | 65.42 ns | 0.7157 ns | 0.6695 ns | 0.79 | 0.01 | } } \ No newline at end of file From 9fa08b22574dbb0cfb041d72b0de49758e899cfd Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 26 Oct 2018 15:18:40 +0200 Subject: [PATCH 234/381] Vector4ConversionThreshold --- .../PixelFormats/PixelOperations{TPixel}.cs | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index c3d8e23b91..668b2d0310 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -17,6 +17,12 @@ namespace SixLabors.ImageSharp.PixelFormats public partial class PixelOperations where TPixel : struct, IPixel { + /// + /// It's not worth to bother the transitive pixel conversion method below this limit. + /// The value depends on the actual gain brought by the SIMD characteristics of the executing CPU and JIT. + /// + private static readonly int Vector4ConversionThreshold = CalculateVector4ConversionThreshold(); + /// /// Gets the global instance for the pixel type /// @@ -183,7 +189,7 @@ namespace SixLabors.ImageSharp.PixelFormats int count = sourcePixels.Length; // Not worth for small buffers: - if (count < 128) + if (count < Vector4ConversionThreshold) { ToVector4DefaultImpl(sourcePixels, destVectors); return; @@ -218,7 +224,7 @@ namespace SixLabors.ImageSharp.PixelFormats int count = sourceVectors.Length; // Not worth for small buffers: - if (count < 128) + if (count < Vector4ConversionThreshold) { FromVector4DefaultImpl(sourceVectors, destPixels); return; @@ -263,5 +269,15 @@ namespace SixLabors.ImageSharp.PixelFormats dp = sp.ToVector4(); } } + + private static int CalculateVector4ConversionThreshold() + { + if (!Vector.IsHardwareAccelerated) + { + return int.MaxValue; + } + + return SimdUtils.ExtendedIntrinsics.IsAvailable && SimdUtils.IsAvx2CompatibleArchitecture ? 256 : 128; + } } } \ No newline at end of file From 5a1cd3ade47a999f2711e2abe44f42d04e0405d6 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 26 Oct 2018 15:51:53 +0200 Subject: [PATCH 235/381] avoid allocation in RunRgba32CompatibleToVector4Conversion --- .../PixelFormats/PixelOperations{TPixel}.cs | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 668b2d0310..9238e1b478 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -171,6 +171,8 @@ namespace SixLabors.ImageSharp.PixelFormats } } + // TODO: The Vector4 helpers should be moved to a utility class. + /// /// Provides an efficient default implementation for and /// which is applicable for -compatible pixel types where @@ -195,15 +197,19 @@ namespace SixLabors.ImageSharp.PixelFormats return; } - using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count)) - { - Span tempSpan = tempBuffer.Memory.Span; - this.ToRgba32(configuration, sourcePixels, tempSpan); + // Using the last quarter of 'destVectors' as a temporary buffer to avoid allocation: + int countWithoutLastItem = count - 1; + ReadOnlySpan reducedSource = sourcePixels.Slice(0, countWithoutLastItem); + Span lastQuarterOfDestBuffer = MemoryMarshal.Cast(destVectors).Slice((3 * count) + 1, countWithoutLastItem); + this.ToRgba32(configuration, reducedSource, lastQuarterOfDestBuffer); - SimdUtils.BulkConvertByteToNormalizedFloat( - MemoryMarshal.Cast(tempSpan), - MemoryMarshal.Cast(destVectors)); - } + // 'destVectors' and 'lastQuarterOfDestBuffer' are ovelapping buffers, + // but we are always reading/writing at different positions: + SimdUtils.BulkConvertByteToNormalizedFloat( + MemoryMarshal.Cast(lastQuarterOfDestBuffer), + MemoryMarshal.Cast(destVectors.Slice(0, countWithoutLastItem))); + + destVectors[countWithoutLastItem] = sourcePixels[countWithoutLastItem].ToVector4(); } /// @@ -230,6 +236,8 @@ namespace SixLabors.ImageSharp.PixelFormats return; } + // For the opposite direction it's not easy to implement the trick used in RunRgba32CompatibleToVector4Conversion, + // so let's allocate a temporary buffer as usually: using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count)) { Span tempSpan = tempBuffer.Memory.Span; From 31369c7435dae33a9578e991208bcfb480c2ecdc Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 26 Oct 2018 16:35:02 +0200 Subject: [PATCH 236/381] refactor Vector4 implementation code from PixelOperation to Vector4Converters --- .../Argb32.PixelOperations.Generated.cs | 9 +- .../Bgr24.PixelOperations.Generated.cs | 9 +- .../Bgra32.PixelOperations.Generated.cs | 9 +- .../Gray16.PixelOperations.Generated.cs | 1 + .../Gray8.PixelOperations.Generated.cs | 1 + .../Rgb24.PixelOperations.Generated.cs | 9 +- .../Rgb48.PixelOperations.Generated.cs | 1 + .../Rgba32.PixelOperations.Generated.cs | 1 + .../Rgba64.PixelOperations.Generated.cs | 1 + .../Generated/_Common.ttinclude | 9 +- .../PixelFormats/PixelOperations{TPixel}.cs | 147 +---------------- .../{ => Utils}/PixelConverter.cs | 3 +- .../{ => Utils}/PixelExtensions.cs | 2 +- .../Utils/Vector4Converters.Default.cs | 89 ++++++++++ .../Utils/Vector4Converters.RgbaCompatible.cs | 154 ++++++++++++++++++ .../Color/Bulk/ToVector4_Bgra32.cs | 21 +++ .../PixelConversion_ConvertFromRgba32.cs | 1 + .../PixelFormats/PixelConverterTests.cs | 1 + 18 files changed, 302 insertions(+), 166 deletions(-) rename src/ImageSharp/PixelFormats/{ => Utils}/PixelConverter.cs (98%) rename src/ImageSharp/PixelFormats/{ => Utils}/PixelExtensions.cs (93%) create mode 100644 src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs create mode 100644 src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs index e6b8922e9d..6449351cca 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs @@ -3,6 +3,7 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; using System.Buffers; using System.Numerics; @@ -45,25 +46,25 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); } /// internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); } /// internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); } /// internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); } /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs index 9b1740013d..9232cf4549 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs @@ -3,6 +3,7 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; using System.Buffers; using System.Numerics; @@ -45,25 +46,25 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); } /// internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); } /// internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); } /// internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs index 37d6b72d71..4f56b75c5a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs @@ -3,6 +3,7 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; using System.Buffers; using System.Numerics; @@ -45,25 +46,25 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); } /// internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); } /// internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); } /// internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); } /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs index 638db1d0d8..81882185d1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs @@ -3,6 +3,7 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; using System.Buffers; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs index 6bf0693c2c..f6678a4f87 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs @@ -3,6 +3,7 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; using System.Buffers; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs index 6ff87eb385..aae8b2f637 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs @@ -3,6 +3,7 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; using System.Buffers; using System.Numerics; @@ -45,25 +46,25 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); } /// internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); } /// internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); } /// internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs index 9b4584d767..c828053a4c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs @@ -3,6 +3,7 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; using System.Buffers; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs index 8e15ca1f4d..9c29bd0445 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs @@ -3,6 +3,7 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; using System.Buffers; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs index caaba78094..db9cb84bec 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs @@ -3,6 +3,7 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; using System.Buffers; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude index 4501f4972e..cc8cb0e2fc 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude @@ -8,6 +8,7 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; using System.Buffers; using System.Numerics; @@ -114,25 +115,25 @@ using System.Runtime.InteropServices; /// internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span<<#=pixelType#>> destPixels) { - this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); } /// internal override void ToVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) { - this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); } /// internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span<<#=pixelType#>> destPixels) { - this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); } /// internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) { - this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); } <#+ diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 9238e1b478..f4eb19be33 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -17,12 +17,6 @@ namespace SixLabors.ImageSharp.PixelFormats public partial class PixelOperations where TPixel : struct, IPixel { - /// - /// It's not worth to bother the transitive pixel conversion method below this limit. - /// The value depends on the actual gain brought by the SIMD characteristics of the executing CPU and JIT. - /// - private static readonly int Vector4ConversionThreshold = CalculateVector4ConversionThreshold(); - /// /// Gets the global instance for the pixel type /// @@ -42,7 +36,7 @@ namespace SixLabors.ImageSharp.PixelFormats Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); - FromVector4DefaultImpl(sourceVectors, destPixels); + Utils.Vector4Converters.Default.DangerousFromVector4(sourceVectors, destPixels); } /// @@ -59,7 +53,7 @@ namespace SixLabors.ImageSharp.PixelFormats Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); - ToVector4DefaultImpl(sourcePixels, destVectors); + Utils.Vector4Converters.Default.DangerousToVector4(sourcePixels, destVectors); } /// @@ -76,15 +70,7 @@ namespace SixLabors.ImageSharp.PixelFormats Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); - ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); - ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); - - for (int i = 0; i < sourceVectors.Length; i++) - { - ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - dp.FromScaledVector4(sp); - } + Utils.Vector4Converters.Default.DangerousFromScaledVector4(sourceVectors, destinationColors); } /// @@ -101,15 +87,7 @@ namespace SixLabors.ImageSharp.PixelFormats Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); - ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); - ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); - - for (int i = 0; i < sourceColors.Length; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); - ref Vector4 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToScaledVector4(); - } + Utils.Vector4Converters.Default.DangerousToScaledVector4(sourceColors, destinationVectors); } /// @@ -170,122 +148,5 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromScaledVector4(sp.ToScaledVector4()); } } - - // TODO: The Vector4 helpers should be moved to a utility class. - - /// - /// Provides an efficient default implementation for and - /// which is applicable for -compatible pixel types where - /// returns the same scaled result as . - /// The method is works by internally converting to a therefore it's not applicable for that type! - /// - [MethodImpl(InliningOptions.ShortMethod)] - internal void RunRgba32CompatibleToVector4Conversion( - Configuration configuration, - ReadOnlySpan sourcePixels, - Span destVectors) - { - Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); - - int count = sourcePixels.Length; - - // Not worth for small buffers: - if (count < Vector4ConversionThreshold) - { - ToVector4DefaultImpl(sourcePixels, destVectors); - return; - } - - // Using the last quarter of 'destVectors' as a temporary buffer to avoid allocation: - int countWithoutLastItem = count - 1; - ReadOnlySpan reducedSource = sourcePixels.Slice(0, countWithoutLastItem); - Span lastQuarterOfDestBuffer = MemoryMarshal.Cast(destVectors).Slice((3 * count) + 1, countWithoutLastItem); - this.ToRgba32(configuration, reducedSource, lastQuarterOfDestBuffer); - - // 'destVectors' and 'lastQuarterOfDestBuffer' are ovelapping buffers, - // but we are always reading/writing at different positions: - SimdUtils.BulkConvertByteToNormalizedFloat( - MemoryMarshal.Cast(lastQuarterOfDestBuffer), - MemoryMarshal.Cast(destVectors.Slice(0, countWithoutLastItem))); - - destVectors[countWithoutLastItem] = sourcePixels[countWithoutLastItem].ToVector4(); - } - - /// - /// Provides an efficient default implementation for and - /// which is applicable for -compatible pixel types where - /// returns the same scaled result as . - /// The method is works by internally converting to a therefore it's not applicable for that type! - /// - [MethodImpl(InliningOptions.ShortMethod)] - internal void RunRgba32CompatibleFromVector4Conversion( - Configuration configuration, - ReadOnlySpan sourceVectors, - Span destPixels) - { - Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); - - int count = sourceVectors.Length; - - // Not worth for small buffers: - if (count < Vector4ConversionThreshold) - { - FromVector4DefaultImpl(sourceVectors, destPixels); - return; - } - - // For the opposite direction it's not easy to implement the trick used in RunRgba32CompatibleToVector4Conversion, - // so let's allocate a temporary buffer as usually: - using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count)) - { - Span tempSpan = tempBuffer.Memory.Span; - - SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( - MemoryMarshal.Cast(sourceVectors), - MemoryMarshal.Cast(tempSpan)); - - this.FromRgba32(configuration, tempSpan, destPixels); - } - } - - [MethodImpl(InliningOptions.ShortMethod)] - private static void FromVector4DefaultImpl(ReadOnlySpan sourceVectors, Span destPixels) - { - ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - for (int i = 0; i < sourceVectors.Length; i++) - { - ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - dp.FromVector4(sp); - } - } - - [MethodImpl(InliningOptions.ShortMethod)] - private static void ToVector4DefaultImpl(ReadOnlySpan sourcePixels, Span destVectors) - { - ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Vector4 destRef = ref MemoryMarshal.GetReference(destVectors); - - for (int i = 0; i < sourcePixels.Length; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); - ref Vector4 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToVector4(); - } - } - - private static int CalculateVector4ConversionThreshold() - { - if (!Vector.IsHardwareAccelerated) - { - return int.MaxValue; - } - - return SimdUtils.ExtendedIntrinsics.IsAvailable && SimdUtils.IsAvx2CompatibleArchitecture ? 256 : 128; - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelConverter.cs b/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs similarity index 98% rename from src/ImageSharp/PixelFormats/PixelConverter.cs rename to src/ImageSharp/PixelFormats/Utils/PixelConverter.cs index 8fde490fda..2336dbee74 100644 --- a/src/ImageSharp/PixelFormats/PixelConverter.cs +++ b/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs @@ -1,11 +1,10 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Buffers.Binary; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.PixelFormats +namespace SixLabors.ImageSharp.PixelFormats.Utils { /// /// Contains optimized implementations for conversion between pixel formats. diff --git a/src/ImageSharp/PixelFormats/PixelExtensions.cs b/src/ImageSharp/PixelFormats/Utils/PixelExtensions.cs similarity index 93% rename from src/ImageSharp/PixelFormats/PixelExtensions.cs rename to src/ImageSharp/PixelFormats/Utils/PixelExtensions.cs index 175696ab63..2284b8fc27 100644 --- a/src/ImageSharp/PixelFormats/PixelExtensions.cs +++ b/src/ImageSharp/PixelFormats/Utils/PixelExtensions.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -namespace SixLabors.ImageSharp.PixelFormats +namespace SixLabors.ImageSharp.PixelFormats.Utils { /// /// Low-performance extension methods to help conversion syntax, suitable for testing purposes. diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs new file mode 100644 index 0000000000..139dbfa10f --- /dev/null +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs @@ -0,0 +1,89 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.PixelFormats.Utils +{ + /// + /// Helper class for (bulk) conversion of buffers to/from other buffer types. + /// + internal static partial class Vector4Converters + { + /// + /// Provides default implementations for batched to/from conversion. + /// WARNING: The methods are operating without bounds checking and input validation! + /// Input validation is the responsibility of the caller! + /// + public static class Default + { + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousFromVector4( + ReadOnlySpan sourceVectors, + Span destPixels) + where TPixel : struct, IPixel + { + ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); + ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourceVectors.Length; i++) + { + ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + dp.FromVector4(sp); + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousToVector4( + ReadOnlySpan sourcePixels, + Span destVectors) + where TPixel : struct, IPixel + { + ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Vector4 destRef = ref MemoryMarshal.GetReference(destVectors); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref Vector4 dp = ref Unsafe.Add(ref destRef, i); + dp = sp.ToVector4(); + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousFromScaledVector4( + ReadOnlySpan sourceVectors, + Span destinationColors) + where TPixel : struct, IPixel + { + ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); + ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); + + for (int i = 0; i < sourceVectors.Length; i++) + { + ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + dp.FromScaledVector4(sp); + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousToScaledVector4( + ReadOnlySpan sourceColors, + Span destinationVectors) + where TPixel : struct, IPixel + { + ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); + ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); + + for (int i = 0; i < sourceColors.Length; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref Vector4 dp = ref Unsafe.Add(ref destRef, i); + dp = sp.ToScaledVector4(); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs new file mode 100644 index 0000000000..7c57fe4fbd --- /dev/null +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs @@ -0,0 +1,154 @@ +using System; +using System.Buffers; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.PixelFormats.Utils +{ + /// + /// Contains + /// + internal static partial class Vector4Converters + { + /// + /// Provides efficient implementations for batched to/from conversion. + /// which is applicable for -compatible pixel types where + /// returns the same scaled result as . + /// The method is works by internally converting to a therefore it's not applicable for that type! + /// + public static class RgbaCompatible + { + /// + /// It's not worth to bother the transitive pixel conversion method below this limit. + /// The value depends on the actual gain brought by the SIMD characteristics of the executing CPU and JIT. + /// + private static readonly int Vector4ConversionThreshold = CalculateVector4ConversionThreshold(); + + /// + /// Provides an efficient default implementation for + /// and + /// which is applicable for -compatible pixel types where + /// returns the same scaled result as . + /// The method is works by internally converting to a therefore it's not applicable for that type! + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void ToVector4( + Configuration configuration, + PixelOperations pixelOperations, + ReadOnlySpan sourcePixels, + Span destVectors, + bool scaled) + where TPixel : struct, IPixel + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); + + int count = sourcePixels.Length; + + // Not worth for small buffers: + if (count < Vector4ConversionThreshold) + { + ToVector4Fallback(sourcePixels, destVectors, scaled); + + return; + } + + // Using the last quarter of 'destVectors' as a temporary buffer to avoid allocation: + int countWithoutLastItem = count - 1; + ReadOnlySpan reducedSource = sourcePixels.Slice(0, countWithoutLastItem); + Span lastQuarterOfDestBuffer = MemoryMarshal.Cast(destVectors).Slice((3 * count) + 1, countWithoutLastItem); + pixelOperations.ToRgba32(configuration, reducedSource, lastQuarterOfDestBuffer); + + // 'destVectors' and 'lastQuarterOfDestBuffer' are ovelapping buffers, + // but we are always reading/writing at different positions: + SimdUtils.BulkConvertByteToNormalizedFloat( + MemoryMarshal.Cast(lastQuarterOfDestBuffer), + MemoryMarshal.Cast(destVectors.Slice(0, countWithoutLastItem))); + + destVectors[countWithoutLastItem] = sourcePixels[countWithoutLastItem].ToVector4(); + } + + /// + /// Provides an efficient default implementation for + /// and + /// which is applicable for -compatible pixel types where + /// returns the same scaled result as . + /// The method is works by internally converting to a therefore it's not applicable for that type! + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void FromVector4( + Configuration configuration, + PixelOperations pixelOperations, + ReadOnlySpan sourceVectors, + Span destPixels, + bool scaled) + where TPixel : struct, IPixel + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); + + int count = sourceVectors.Length; + + // Not worth for small buffers: + if (count < Vector4ConversionThreshold) + { + FromVector4Fallback(sourceVectors, destPixels, scaled); + + return; + } + + // For the opposite direction it's not easy to implement the trick used in RunRgba32CompatibleToVector4Conversion, + // so let's allocate a temporary buffer as usually: + using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count)) + { + Span tempSpan = tempBuffer.Memory.Span; + + SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( + MemoryMarshal.Cast(sourceVectors), + MemoryMarshal.Cast(tempSpan)); + + pixelOperations.FromRgba32(configuration, tempSpan, destPixels); + } + } + + [MethodImpl(InliningOptions.ColdPath)] + private static void ToVector4Fallback(ReadOnlySpan sourcePixels, Span destVectors, bool scaled) + where TPixel : struct, IPixel + { + if (scaled) + { + Default.DangerousToScaledVector4(sourcePixels, destVectors); + } + else + { + Default.DangerousToVector4(sourcePixels, destVectors); + } + } + + [MethodImpl(InliningOptions.ColdPath)] + private static void FromVector4Fallback(ReadOnlySpan sourceVectors, Span destPixels, bool scaled) + where TPixel : struct, IPixel + { + if (scaled) + { + Default.DangerousFromScaledVector4(sourceVectors, destPixels); + } + else + { + Default.DangerousFromVector4(sourceVectors, destPixels); + } + } + + private static int CalculateVector4ConversionThreshold() + { + if (!Vector.IsHardwareAccelerated) + { + return int.MaxValue; + } + + return SimdUtils.ExtendedIntrinsics.IsAvailable && SimdUtils.IsAvx2CompatibleArchitecture ? 256 : 128; + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs index 028bfe46f8..39702d5253 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs @@ -16,5 +16,26 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.source.GetSpan(), this.destination.GetSpan()); } + + // RESULTS: + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ---------------------------- |-------- |------ |-----------:|------------:|-----------:|-------:|---------:|-------:|----------:| + // PixelOperations_Base | Clr | 64 | 339.9 ns | 138.30 ns | 7.8144 ns | 1.00 | 0.00 | 0.0072 | 24 B | + // PixelOperations_Specialized | Clr | 64 | 338.1 ns | 13.30 ns | 0.7515 ns | 0.99 | 0.02 | - | 0 B | + // | | | | | | | | | | + // PixelOperations_Base | Core | 64 | 245.6 ns | 29.05 ns | 1.6413 ns | 1.00 | 0.00 | 0.0072 | 24 B | + // PixelOperations_Specialized | Core | 64 | 257.1 ns | 37.89 ns | 2.1407 ns | 1.05 | 0.01 | - | 0 B | + // | | | | | | | | | | + // PixelOperations_Base | Clr | 256 | 972.7 ns | 61.98 ns | 3.5020 ns | 1.00 | 0.00 | 0.0057 | 24 B | + // PixelOperations_Specialized | Clr | 256 | 882.9 ns | 126.21 ns | 7.1312 ns | 0.91 | 0.01 | - | 0 B | + // | | | | | | | | | | + // PixelOperations_Base | Core | 256 | 910.0 ns | 90.87 ns | 5.1346 ns | 1.00 | 0.00 | 0.0067 | 24 B | + // PixelOperations_Specialized | Core | 256 | 448.4 ns | 15.77 ns | 0.8910 ns | 0.49 | 0.00 | - | 0 B | + // | | | | | | | | | | + // PixelOperations_Base | Clr | 2048 | 6,951.8 ns | 1,299.01 ns | 73.3963 ns | 1.00 | 0.00 | - | 24 B | + // PixelOperations_Specialized | Clr | 2048 | 5,852.3 ns | 630.56 ns | 35.6279 ns | 0.84 | 0.01 | - | 0 B | + // | | | | | | | | | | + // PixelOperations_Base | Core | 2048 | 6,937.5 ns | 1,692.19 ns | 95.6121 ns | 1.00 | 0.00 | - | 24 B | + // PixelOperations_Specialized | Core | 2048 | 2,994.5 ns | 1,126.65 ns | 63.6578 ns | 0.43 | 0.01 | - | 0 B | } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs index 424020e2f2..9f1b2721b4 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs @@ -7,6 +7,7 @@ using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.PixelFormats.Utils; namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion { diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs index 9b32f7aeee..c539e9dcf0 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs @@ -1,4 +1,5 @@ using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.PixelFormats.Utils; using Xunit; From 09de1b1cde7a43d35a3759699539b31a27349b67 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 26 Oct 2018 19:43:00 +0200 Subject: [PATCH 237/381] better docs, drop PixelExtensions, fix tests --- .../PixelFormats/Utils/PixelConverter.cs | 12 +++++----- .../PixelFormats/Utils/PixelExtensions.cs | 22 ------------------- .../Drawing/FillLinearGradientBrushTests.cs | 4 +++- .../PixelFormats/Alpha8Tests.cs | 3 ++- .../PixelFormats/Gray16Tests.cs | 3 ++- .../PixelFormats/Gray8Tests.cs | 5 +++-- .../PixelFormats/Rgb24Tests.cs | 3 ++- .../PixelFormats/Rgb48Tests.cs | 3 ++- .../PixelFormats/Rgba1010102Tests.cs | 3 ++- .../PixelFormats/Rgba64Tests.cs | 2 +- .../PixelFormats/Short2Tests.cs | 4 ++-- .../PixelFormats/Short4Tests.cs | 12 ++++++---- .../PixelFormats/UnPackedPixelTests.cs | 6 +++-- .../Quantization/QuantizedImageTests.cs | 3 ++- .../TestUtilities/TestUtils.cs | 7 ++++-- .../Tests/TestImageProviderTests.cs | 3 ++- 16 files changed, 47 insertions(+), 48 deletions(-) delete mode 100644 src/ImageSharp/PixelFormats/Utils/PixelExtensions.cs diff --git a/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs b/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs index 2336dbee74..55a94fc81e 100644 --- a/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs +++ b/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs @@ -12,7 +12,9 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils /// /// Implementations are based on ideas in: /// https://github.com/dotnet/coreclr/blob/master/src/System.Private.CoreLib/shared/System/Buffers/Binary/Reader.cs#L84 - /// The JIT should be able to detect and optimize ROL and ROR patterns. + /// The JIT can detect and optimize rotation idioms ROTL (Rotate Left) + /// and ROTR (Rotate Right) emitting efficient CPU instructions: + /// https://github.com/dotnet/coreclr/pull/1830 /// internal static class PixelConverter { @@ -25,7 +27,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils public static uint ToArgb32(uint packedRgba) { // packedRgba = [aa bb gg rr] - // ROL(8, packedRgba) = [bb gg rr aa] + // ROTL(8, packedRgba) = [bb gg rr aa] return (packedRgba << 8) | (packedRgba >> 24); } @@ -38,7 +40,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils // packedRgba = [aa bb gg rr] // tmp1 = [aa 00 gg 00] // tmp2 = [00 bb 00 rr] - // tmp3=ROL(16, tmp2) = [00 rr 00 bb] + // tmp3=ROTL(16, tmp2) = [00 rr 00 bb] // tmp1 + tmp3 = [aa rr gg bb] uint tmp1 = packedRgba & 0xFF00FF00; uint tmp2 = packedRgba & 0x00FF00FF; @@ -56,7 +58,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils public static uint ToRgba32(uint packedArgb) { // packedArgb = [bb gg rr aa] - // ROR(8, packedArgb) = [aa bb gg rr] + // ROTR(8, packedArgb) = [aa bb gg rr] return (packedArgb >> 8) | (packedArgb << 24); } @@ -94,7 +96,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils // packedRgba = [aa rr gg bb] // tmp1 = [aa 00 gg 00] // tmp2 = [00 rr 00 bb] - // tmp3=ROL(16, tmp2) = [00 bb 00 rr] + // tmp3=ROTL(16, tmp2) = [00 bb 00 rr] // tmp1 + tmp3 = [aa bb gg rr] uint tmp1 = packedBgra & 0xFF00FF00; uint tmp2 = packedBgra & 0x00FF00FF; diff --git a/src/ImageSharp/PixelFormats/Utils/PixelExtensions.cs b/src/ImageSharp/PixelFormats/Utils/PixelExtensions.cs deleted file mode 100644 index 2284b8fc27..0000000000 --- a/src/ImageSharp/PixelFormats/Utils/PixelExtensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.PixelFormats.Utils -{ - /// - /// Low-performance extension methods to help conversion syntax, suitable for testing purposes. - /// - internal static class PixelExtensions - { - /// - /// Returns the result of as a new instance. - /// - public static Rgba32 ToRgba32(this TPixel pixel) - where TPixel : struct, IPixel - { - Rgba32 result = default; - pixel.ToRgba32(ref result); - return result; - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs index 9121649f48..556ec9c9ca 100644 --- a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs @@ -328,7 +328,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing TPixel color = colors[stopColorCodes[i % colors.Length]]; float position = stopPositions[i]; colorStops[i] = new ColorStop(position, color); - coloringVariant.AppendFormat(CultureInfo.InvariantCulture, "{0}@{1};", color.ToRgba32().ToHex(), position); + Rgba32 rgba = default; + color.ToRgba32(ref rgba); + coloringVariant.AppendFormat(CultureInfo.InvariantCulture, "{0}@{1};", rgba.ToHex(), position); } FormattableString variant = $"({startX},{startY})_TO_({endX},{endY})__[{coloringVariant}]"; diff --git a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs index 148b928fac..8f68c9d03f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs @@ -90,7 +90,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var input = new Alpha8(128); var expected = new Rgba32(0, 0, 0, 128); - var actual = input.ToRgba32(); + Rgba32 actual = default; + input.ToRgba32(ref actual); Assert.Equal(expected, actual); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs index 220ca2899a..cb19c031d0 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs @@ -117,7 +117,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var gray = new Gray16(input); // Act - var actual = gray.ToRgba32(); + Rgba32 actual = default; + gray.ToRgba32(ref actual); // Assert Assert.Equal(expected, actual.R); diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs index 988002c099..6a7b20cbed 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs @@ -115,10 +115,11 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var gray = new Gray8(input); // Act - var actual = gray.ToRgba32(); + Rgba32 actual = default; + gray.ToRgba32(ref actual); // Assert - Assert.Equal(input, actual.R); + Assert.Equal(input, actual.R); Assert.Equal(input, actual.G); Assert.Equal(input, actual.B); Assert.Equal(byte.MaxValue, actual.A); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs index a60509146d..92e8d302d4 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -104,7 +104,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public void ToRgba32() { var rgb = new Rgb24(1, 2, 3); - var rgba = rgb.ToRgba32(); + Rgba32 rgba = default; + rgb.ToRgba32(ref rgba); Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index a7f0e5edfc..d30e498609 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -52,7 +52,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(20, 38, 76, 255); // act - var actual = rgba48.ToRgba32(); + Rgba32 actual = default; + rgba48.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs index ad7df30769..a897dd4cdb 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs @@ -79,7 +79,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(25, 0, 128, 0); // act - var actual = rgba.ToRgba32(); + Rgba32 actual = default; + rgba.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index 564c26b8b1..3e5d7a56ed 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(20, 38, 76, 115); // act - actual = rgba64.ToRgba32(); + rgba64.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs index 725e1a0d14..c9a3b33c9a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs @@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(128, 127, 0, 255); // act - actual = short2.ToRgba32(); + short2.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short2.FromRgba32(expected); - actual = short2.ToRgba32(); + short2.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs index b19917f34a..247342a053 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs @@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(172, 177, 243, 128); // act - actual = shortValue.ToRgba32(); + shortValue.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); @@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short4.FromRgba32(expected); - actual = short4.ToRgba32(); + short4.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); @@ -124,7 +124,9 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short4.FromBgra32(expected); - actual.FromRgba32(short4.ToRgba32()); + Rgba32 temp = default; + short4.ToRgba32(ref temp); + actual.FromRgba32(temp); // assert Assert.Equal(expected, actual); @@ -140,7 +142,9 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short4.FromArgb32(expected); - actual.FromRgba32(short4.ToRgba32()); + Rgba32 temp = default; + short4.ToRgba32(ref temp); + actual.FromRgba32(temp); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs index 29c97ce35f..bd8c647421 100644 --- a/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs @@ -84,8 +84,10 @@ namespace SixLabors.ImageSharp.Tests.Colors var color = new Rgba32(24, 48, 96, 192); var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); - var rgba = color.ToRgba32(); - var rgbaVector = colorVector.ToRgba32(); + Rgba32 rgba = default; + Rgba32 rgbaVector = default; + color.ToRgba32(ref rgba); + colorVector.ToRgba32(ref rgbaVector); Assert.Equal(rgba, rgbaVector); } diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index fa855aef77..577dc83c53 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -106,9 +106,10 @@ namespace SixLabors.ImageSharp.Tests { // Transparent pixels are much more likely to be found at the end of a palette int index = -1; + Rgba32 trans = default; for (int i = quantized.Palette.Length - 1; i >= 0; i--) { - var trans = quantized.Palette[i].ToRgba32(); + quantized.Palette[i].ToRgba32(ref trans); if (trans.Equals(default)) { diff --git a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs index e6a5ffc84b..d7755ff7a4 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs @@ -80,8 +80,11 @@ namespace SixLabors.ImageSharp.Tests } else { - rgb1 = ca.ToRgba32().Rgb; - rgb2 = cb.ToRgba32().Rgb; + Rgba32 rgba = default; + ca.ToRgba32(ref rgba); + rgb1 = rgba.Rgb; + cb.ToRgba32(ref rgba); + rgb2 = rgba.Rgb; if (!rgb1.Equals(rgb2)) { diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs index 1d284af15e..a8140e39d4 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs @@ -275,11 +275,12 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(20, img.Height); Buffer2D pixels = img.GetRootFramePixelBuffer(); + Rgba32 rgba = default; for (int y = 0; y < pixels.Height; y++) { for (int x = 0; x < pixels.Width; x++) { - var rgba = pixels[x, y].ToRgba32(); + pixels[x, y].ToRgba32(ref rgba); Assert.Equal(255, rgba.R); Assert.Equal(100, rgba.G); From 16018e5c6a44c3038d70797469e2c8eca43e2f0a Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 26 Oct 2018 20:04:19 +0200 Subject: [PATCH 238/381] refactor PixelOperationsTests --- tests/ImageSharp.Tests/ConfigurationTests.cs | 1 + .../ImageSharp.Tests/GraphicsOptionsTests.cs | 21 + ...elOperationsTests.Argb32OperationsTests.cs | 22 + ...xelOperationsTests.Bgr24OperationsTests.cs | 21 + ...elOperationsTests.Bgra32OperationsTests.cs | 21 + ...elOperationsTests.Gray16OperationsTests.cs | 111 +++++ ...xelOperationsTests.Gray8OperationsTests.cs | 111 +++++ ...xelOperationsTests.Rgb48OperationsTests.cs | 21 + ...elOperationsTests.Rgba32OperationsTests.cs | 43 ++ ...elOperationsTests.Rgba64OperationsTests.cs | 21 + ...erationsTests.RgbaVectorOperationsTests.cs | 21 + .../PixelOperationsTests.cs | 394 +++--------------- 12 files changed, 476 insertions(+), 332 deletions(-) create mode 100644 tests/ImageSharp.Tests/GraphicsOptionsTests.cs create mode 100644 tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs create mode 100644 tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs create mode 100644 tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs create mode 100644 tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs create mode 100644 tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs create mode 100644 tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs create mode 100644 tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs create mode 100644 tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs create mode 100644 tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs rename tests/ImageSharp.Tests/PixelFormats/{ => PixelOperations}/PixelOperationsTests.cs (63%) diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs index 963d674466..208387e6d1 100644 --- a/tests/ImageSharp.Tests/ConfigurationTests.cs +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -6,6 +6,7 @@ using System.Linq; using Moq; using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.IO; + using Xunit; // ReSharper disable InconsistentNaming diff --git a/tests/ImageSharp.Tests/GraphicsOptionsTests.cs b/tests/ImageSharp.Tests/GraphicsOptionsTests.cs new file mode 100644 index 0000000000..6ff38626d6 --- /dev/null +++ b/tests/ImageSharp.Tests/GraphicsOptionsTests.cs @@ -0,0 +1,21 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests +{ + public class GraphicsOptionsTests + { + [Fact] + public void IsOpaqueColor() + { + Assert.True(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions(true, 0.5f).IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Transparent)); + Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Lighten, 1).IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(Rgba32.Red)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs new file mode 100644 index 0000000000..875ba0cba4 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs @@ -0,0 +1,22 @@ +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Argb32OperationsTests : PixelOperationsTests + { + + public Argb32OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs new file mode 100644 index 0000000000..879712a3e5 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs @@ -0,0 +1,21 @@ +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Bgr24OperationsTests : PixelOperationsTests + { + public Bgr24OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs new file mode 100644 index 0000000000..963a9dae6d --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs @@ -0,0 +1,21 @@ +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Bgra32OperationsTests : PixelOperationsTests + { + public Bgra32OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs new file mode 100644 index 0000000000..1afa65240a --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs @@ -0,0 +1,111 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Gray16OperationsTests : PixelOperationsTests + { + public Gray16OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void FromGray8Bytes(int count) + { + byte[] source = CreateByteTestData(count); + var expected = new Gray16[count]; + + for (int i = 0; i < count; i++) + { + expected[i].FromGray8(new Gray8(source[i])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.FromGray8Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray8Bytes(int count) + { + Gray16[] source = CreatePixelTestData(count); + byte[] expected = new byte[count]; + var gray = default(Gray8); + + for (int i = 0; i < count; i++) + { + gray.FromScaledVector4(source[i].ToScaledVector4()); + expected[i] = gray.PackedValue; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray8Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void FromGray16Bytes(int count) + { + byte[] source = CreateByteTestData(count * 2); + Span sourceSpan = source.AsSpan(); + var expected = new Gray16[count]; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + expected[i].FromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); + } + + TestOperation( + source, + expected, + (s, d) => Operations.FromGray16Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray16Bytes(int count) + { + Gray16[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 2]; + Gray16 gray = default; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + gray.FromScaledVector4(source[i].ToScaledVector4()); + OctetBytes bytes = Unsafe.As(ref gray); + expected[i2] = bytes[0]; + expected[i2 + 1] = bytes[1]; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray16Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs new file mode 100644 index 0000000000..4112d201b5 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs @@ -0,0 +1,111 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Gray8OperationsTests : PixelOperationsTests + { + public Gray8OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void FromGray8Bytes(int count) + { + byte[] source = CreateByteTestData(count); + var expected = new Gray8[count]; + + for (int i = 0; i < count; i++) + { + expected[i].FromGray8(new Gray8(source[i])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.FromGray8Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray8Bytes(int count) + { + Gray8[] source = CreatePixelTestData(count); + byte[] expected = new byte[count]; + var gray = default(Gray8); + + for (int i = 0; i < count; i++) + { + gray.FromScaledVector4(source[i].ToScaledVector4()); + expected[i] = gray.PackedValue; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray8Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void FromGray16Bytes(int count) + { + byte[] source = CreateByteTestData(count * 2); + Span sourceSpan = source.AsSpan(); + var expected = new Gray8[count]; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + expected[i].FromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); + } + + TestOperation( + source, + expected, + (s, d) => Operations.FromGray16Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray16Bytes(int count) + { + Gray8[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 2]; + Gray16 gray = default; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + gray.FromScaledVector4(source[i].ToScaledVector4()); + OctetBytes bytes = Unsafe.As(ref gray); + expected[i2] = bytes[0]; + expected[i2 + 1] = bytes[1]; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray16Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs new file mode 100644 index 0000000000..68b67fce27 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs @@ -0,0 +1,21 @@ +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Rgb48OperationsTests : PixelOperationsTests + { + public Rgb48OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs new file mode 100644 index 0000000000..38cc978930 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs @@ -0,0 +1,43 @@ +using System.Buffers; +using System.Numerics; + +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Rgba32OperationsTests : PixelOperationsTests + { + public Rgba32OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + + [Fact(Skip = SkipProfilingBenchmarks)] + public void Benchmark_ToVector4() + { + const int times = 200000; + const int count = 1024; + + using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) + using (IMemoryOwner dest = Configuration.Default.MemoryAllocator.Allocate(count)) + { + this.Measure( + times, + () => PixelOperations.Instance.ToVector4( + this.Configuration, + source.GetSpan(), + dest.GetSpan())); + } + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs new file mode 100644 index 0000000000..47738ac609 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs @@ -0,0 +1,21 @@ +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Rgba64OperationsTests : PixelOperationsTests + { + public Rgba64OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs new file mode 100644 index 0000000000..7272dfb781 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs @@ -0,0 +1,21 @@ +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class RgbaVectorOperationsTests : PixelOperationsTests + { + public RgbaVectorOperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs similarity index 63% rename from tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs rename to tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs index e66ca9a714..d9845e4741 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs @@ -6,335 +6,65 @@ using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; + using Xunit; using Xunit.Abstractions; -namespace SixLabors.ImageSharp.Tests.PixelFormats +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations { - public class PixelOperationsTests + public partial class PixelOperationsTests { - public const string SkipProfilingBenchmarks = -#if true - "Profiling benchmark - enable manually!"; -#else - null; -#endif - - public class Argb32OperationsTests : PixelOperationsTests - { - - public Argb32OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - } - - public class Bgr24OperationsTests : PixelOperationsTests - { - public Bgr24OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - } - - public class Bgra32OperationsTests : PixelOperationsTests - { - public Bgra32OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - } - - public class Gray8OperationsTests : PixelOperationsTests - { - public Gray8OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void FromGray8Bytes(int count) - { - byte[] source = CreateByteTestData(count); - var expected = new Gray8[count]; - - for (int i = 0; i < count; i++) - { - expected[i].FromGray8(new Gray8(source[i])); - } - - TestOperation( - source, - expected, - (s, d) => Operations.FromGray8Bytes(this.Configuration, s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToGray8Bytes(int count) - { - Gray8[] source = CreatePixelTestData(count); - byte[] expected = new byte[count]; - var gray = default(Gray8); - - for (int i = 0; i < count; i++) - { - gray.FromScaledVector4(source[i].ToScaledVector4()); - expected[i] = gray.PackedValue; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToGray8Bytes(this.Configuration, s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void FromGray16Bytes(int count) - { - byte[] source = CreateByteTestData(count * 2); - Span sourceSpan = source.AsSpan(); - var expected = new Gray8[count]; - - for (int i = 0; i < count; i++) - { - int i2 = i * 2; - expected[i].FromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); - } - - TestOperation( - source, - expected, - (s, d) => Operations.FromGray16Bytes(this.Configuration, s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToGray16Bytes(int count) - { - Gray8[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 2]; - Gray16 gray = default; - - for (int i = 0; i < count; i++) - { - int i2 = i * 2; - gray.FromScaledVector4(source[i].ToScaledVector4()); - OctetBytes bytes = Unsafe.As(ref gray); - expected[i2] = bytes[0]; - expected[i2 + 1] = bytes[1]; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToGray16Bytes(this.Configuration, s, d.GetSpan(), count) - ); - } - } - - public class Gray16OperationsTests : PixelOperationsTests - { - public Gray16OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void FromGray8Bytes(int count) - { - byte[] source = CreateByteTestData(count); - var expected = new Gray16[count]; - - for (int i = 0; i < count; i++) - { - expected[i].FromGray8(new Gray8(source[i])); - } - - TestOperation( - source, - expected, - (s, d) => Operations.FromGray8Bytes(this.Configuration, s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToGray8Bytes(int count) - { - Gray16[] source = CreatePixelTestData(count); - byte[] expected = new byte[count]; - var gray = default(Gray8); - - for (int i = 0; i < count; i++) - { - gray.FromScaledVector4(source[i].ToScaledVector4()); - expected[i] = gray.PackedValue; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToGray8Bytes(this.Configuration, s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void FromGray16Bytes(int count) - { - byte[] source = CreateByteTestData(count * 2); - Span sourceSpan = source.AsSpan(); - var expected = new Gray16[count]; - - for (int i = 0; i < count; i++) - { - int i2 = i * 2; - expected[i].FromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); - } - - TestOperation( - source, - expected, - (s, d) => Operations.FromGray16Bytes(this.Configuration, s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToGray16Bytes(int count) - { - Gray16[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 2]; - Gray16 gray = default; - - for (int i = 0; i < count; i++) - { - int i2 = i * 2; - gray.FromScaledVector4(source[i].ToScaledVector4()); - OctetBytes bytes = Unsafe.As(ref gray); - expected[i2] = bytes[0]; - expected[i2 + 1] = bytes[1]; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToGray16Bytes(this.Configuration, s, d.GetSpan(), count) - ); - } - } - - public class Rgba32OperationsTests : PixelOperationsTests - { - public Rgba32OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - - [Fact(Skip = SkipProfilingBenchmarks)] - public void Benchmark_ToVector4() - { - const int times = 200000; - const int count = 1024; - - using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) - using (IMemoryOwner dest = Configuration.Default.MemoryAllocator.Allocate(count)) - { - this.Measure( - times, - () => PixelOperations.Instance.ToVector4( - this.Configuration, - source.GetSpan(), - dest.GetSpan())); - } - } - } - - public class Rgb48OperationsTests : PixelOperationsTests - { - public Rgb48OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - } - - public class Rgba64OperationsTests : PixelOperationsTests - { - public Rgba64OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - } - - public class RgbaVectorOperationsTests : PixelOperationsTests - { - public RgbaVectorOperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - } - [Theory] [WithBlankImages(1, 1, PixelTypes.All)] - public void GetGlobalInstance(TestImageProvider _) - where TPixel : struct, IPixel => Assert.NotNull(PixelOperations.Instance); - - [Fact] - public void IsOpaqueColor() - { - Assert.True(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Red)); - Assert.False(new GraphicsOptions(true, 0.5f).IsOpaqueColorWithoutBlending(Rgba32.Red)); - Assert.False(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Transparent)); - Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Lighten, 1).IsOpaqueColorWithoutBlending(Rgba32.Red)); - Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(Rgba32.Red)); - } + public void GetGlobalInstance(TestImageProvider _) + where T : struct, IPixel => Assert.NotNull(PixelOperations.Instance); } public abstract class PixelOperationsTests : MeasureFixture where TPixel : struct, IPixel { + public const string SkipProfilingBenchmarks = +#if true + "Profiling benchmark - enable manually!"; +#else + null; +#endif + protected PixelOperationsTests(ITestOutputHelper output) : base(output) { } - public static TheoryData ArraySizesData => new TheoryData { 0, 1, 2, 7, 16, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 1111 }; + public static TheoryData ArraySizesData => + new TheoryData + { + 0, + 1, + 2, + 7, + 16, + 512, + 513, + 514, + 515, + 516, + 517, + 518, + 519, + 520, + 521, + 522, + 523, + 524, + 525, + 526, + 527, + 528, + 1111 + }; protected Configuration Configuration => Configuration.Default; @@ -390,28 +120,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats ); } - internal static Vector4[] CreateExpectedVector4Data(TPixel[] source) - { - var expected = new Vector4[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i] = source[i].ToVector4(); - } - return expected; - } - - internal static Vector4[] CreateExpectedScaledVector4Data(TPixel[] source) - { - var expected = new Vector4[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i] = source[i].ToScaledVector4(); - } - return expected; - } - [Theory] [MemberData(nameof(ArraySizesData))] public void ToVector4(int count) @@ -769,6 +477,28 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats ); } + internal static Vector4[] CreateExpectedVector4Data(TPixel[] source) + { + var expected = new Vector4[source.Length]; + + for (int i = 0; i < expected.Length; i++) + { + expected[i] = source[i].ToVector4(); + } + return expected; + } + + internal static Vector4[] CreateExpectedScaledVector4Data(TPixel[] source) + { + var expected = new Vector4[source.Length]; + + for (int i = 0; i < expected.Length; i++) + { + expected[i] = source[i].ToScaledVector4(); + } + return expected; + } + internal static void TestOperation( TSource[] source, TDest[] expected, From 633c212bdd45e083f4c4fd2b5de38cd02b95ddd9 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 26 Oct 2018 20:30:48 +0200 Subject: [PATCH 239/381] add header --- .../PixelOperationsTests.Argb32OperationsTests.cs | 5 ++++- .../PixelOperationsTests.Bgr24OperationsTests.cs | 5 ++++- .../PixelOperationsTests.Bgra32OperationsTests.cs | 5 ++++- .../PixelOperationsTests.Gray16OperationsTests.cs | 5 ++++- .../PixelOperationsTests.Gray8OperationsTests.cs | 5 ++++- .../PixelOperationsTests.Rgb48OperationsTests.cs | 5 ++++- .../PixelOperationsTests.Rgba32OperationsTests.cs | 5 ++++- .../PixelOperationsTests.Rgba64OperationsTests.cs | 5 ++++- .../PixelOperationsTests.RgbaVectorOperationsTests.cs | 5 ++++- 9 files changed, 36 insertions(+), 9 deletions(-) diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs index 875ba0cba4..c881ae96ba 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs @@ -1,4 +1,7 @@ -using SixLabors.ImageSharp.PixelFormats; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; using Xunit; using Xunit.Abstractions; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs index 879712a3e5..323d3914cf 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs @@ -1,4 +1,7 @@ -using SixLabors.ImageSharp.PixelFormats; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; using Xunit; using Xunit.Abstractions; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs index 963a9dae6d..1c966951fc 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs @@ -1,4 +1,7 @@ -using SixLabors.ImageSharp.PixelFormats; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; using Xunit; using Xunit.Abstractions; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs index 1afa65240a..c3de335470 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs @@ -1,4 +1,7 @@ -using System; +// 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/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs index 4112d201b5..acd6ef23ac 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs @@ -1,4 +1,7 @@ -using System; +// 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/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs index 68b67fce27..0a28db6b0a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs @@ -1,4 +1,7 @@ -using SixLabors.ImageSharp.PixelFormats; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; using Xunit; using Xunit.Abstractions; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs index 38cc978930..1ecbaf3615 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs @@ -1,4 +1,7 @@ -using System.Buffers; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Buffers; using System.Numerics; using SixLabors.ImageSharp.Memory; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs index 47738ac609..6787602bb2 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs @@ -1,4 +1,7 @@ -using SixLabors.ImageSharp.PixelFormats; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; using Xunit; using Xunit.Abstractions; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs index 7272dfb781..f9cc042a77 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs @@ -1,4 +1,7 @@ -using SixLabors.ImageSharp.PixelFormats; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; using Xunit; using Xunit.Abstractions; From cf7af016bec905f2e7399c57fe638d4dc45b097c Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 26 Oct 2018 20:33:25 +0200 Subject: [PATCH 240/381] fix Sandbox46 build --- tests/ImageSharp.Sandbox46/Program.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/ImageSharp.Sandbox46/Program.cs b/tests/ImageSharp.Sandbox46/Program.cs index 4d89929a03..3a3a7d31cd 100644 --- a/tests/ImageSharp.Sandbox46/Program.cs +++ b/tests/ImageSharp.Sandbox46/Program.cs @@ -3,6 +3,8 @@ // Licensed under the Apache License, Version 2.0. // +using SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations; + namespace SixLabors.ImageSharp.Sandbox46 { using System; From 013d58e3ddc79badd275d5fe6d586b148f8e8761 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Fri, 26 Oct 2018 22:58:35 +0200 Subject: [PATCH 241/381] Added missing length check that caused an ArgumentNullException (#750) --- .../Common/Extensions/EncoderExtensions.cs | 5 +++ .../Common/EncoderExtensionsTests.cs | 32 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs diff --git a/src/ImageSharp/Common/Extensions/EncoderExtensions.cs b/src/ImageSharp/Common/Extensions/EncoderExtensions.cs index 82899863c9..086dbee35a 100644 --- a/src/ImageSharp/Common/Extensions/EncoderExtensions.cs +++ b/src/ImageSharp/Common/Extensions/EncoderExtensions.cs @@ -20,6 +20,11 @@ namespace SixLabors.ImageSharp /// The string. public static string GetString(this Encoding encoding, ReadOnlySpan buffer) { + if (buffer.Length == 0) + { + return null; + } + fixed (byte* bytes = buffer) { return encoding.GetString(bytes, buffer.Length); diff --git a/tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs b/tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs new file mode 100644 index 0000000000..ec1ae65d6d --- /dev/null +++ b/tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs @@ -0,0 +1,32 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Text; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Common +{ + public class EncoderExtensionsTests + { + [Fact] + public void GetString_EmptyBuffer_ReturnsNull() + { + var buffer = new ReadOnlySpan(); + + string result = Encoding.UTF8.GetString(buffer); + + Assert.Null(result); + } + + [Fact] + public void GetString_Buffer_ReturnsString() + { + var buffer = new ReadOnlySpan(new byte[] { 73, 109, 97, 103, 101, 83, 104, 97, 114, 112 }); + + string result = Encoding.UTF8.GetString(buffer); + + Assert.Equal("ImageSharp", result); + } + } +} From a2a4bcbfab0fc2dcaf29247800a8830249824736 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Fri, 26 Oct 2018 23:32:35 +0200 Subject: [PATCH 242/381] Return empty string instead of null. --- src/ImageSharp/Common/Extensions/EncoderExtensions.cs | 2 +- tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Common/Extensions/EncoderExtensions.cs b/src/ImageSharp/Common/Extensions/EncoderExtensions.cs index 086dbee35a..59c878485d 100644 --- a/src/ImageSharp/Common/Extensions/EncoderExtensions.cs +++ b/src/ImageSharp/Common/Extensions/EncoderExtensions.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp { if (buffer.Length == 0) { - return null; + return string.Empty; } fixed (byte* bytes = buffer) diff --git a/tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs b/tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs index ec1ae65d6d..e1b4fc790c 100644 --- a/tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs +++ b/tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs @@ -10,13 +10,13 @@ namespace SixLabors.ImageSharp.Tests.Common public class EncoderExtensionsTests { [Fact] - public void GetString_EmptyBuffer_ReturnsNull() + public void GetString_EmptyBuffer_ReturnsEmptyString() { var buffer = new ReadOnlySpan(); string result = Encoding.UTF8.GetString(buffer); - Assert.Null(result); + Assert.Equal(string.Empty, result); } [Fact] From 25bc07427310d2f3445172b828c734677784f185 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 27 Oct 2018 00:09:33 +0200 Subject: [PATCH 243/381] imrpoved accuracy for Gray8 conversion --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 2 +- .../PixelImplementations/Gray8.cs | 15 +- .../PixelFormats/Gray8Tests.cs | 168 +++++++++++++++--- 3 files changed, 158 insertions(+), 27 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 6c52eded5f..402aa79b5f 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp /// The blue component. /// The . [MethodImpl(InliningOptions.ShortMethod)] - public static byte Get8BitBT709Luminance(byte r, byte g, byte b) => (byte)((r * .2126F) + (g * .7152F) + (b * .0722F)); + public static byte Get8BitBT709Luminance(byte r, byte g, byte b) => (byte)((r * .2126F) + (g * .7152F) + (b * .0722F) + 0.5f); /// /// Gets the luminance from the rgb components using the formula as specified by ITU-R Recommendation BT.709. diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs index d23fda7991..b49eb2505d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs @@ -18,6 +18,11 @@ namespace SixLabors.ImageSharp.PixelFormats private static readonly Vector4 Half = new Vector4(0.5F); private const float Average = 1 / 3F; + private static readonly Vector4 Min = new Vector4(0, 0, 0, 1f); + private static readonly Vector4 Max = Vector4.One; + + private static readonly Vector4 Accumulator = new Vector4(255f * Average, 255f * Average, 255f * Average, 0.5f); + /// /// Initializes a new instance of the struct. /// @@ -64,10 +69,12 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromVector4(Vector4 vector) { - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes) * Average; - this.PackedValue = (byte)(vector.X + vector.Y + vector.Z); + vector = Vector4.Max(Min, vector); + vector = Vector4.Min(Max, vector); + + float roundedSum = Vector4.Dot(vector, Accumulator); + + this.PackedValue = (byte)roundedSum; } /// diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs index 988002c099..fcd8da0512 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs @@ -1,14 +1,42 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System.Diagnostics; using System.Numerics; + +using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.PixelFormats; using Xunit; +// ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.PixelFormats { public class Gray8Tests { + public static readonly TheoryData LuminanceData = new TheoryData() + { + 0, + 1, + 2, + 3, + 5, + 13, + 31, + 71, + 73, + 79, + 83, + 109, + 127, + 128, + 131, + 199, + 250, + 251, + 254, + 255 + }; + [Theory] [InlineData(0)] [InlineData(255)] @@ -34,9 +62,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Theory] - [InlineData(0)] - [InlineData(255)] - [InlineData(30)] + [MemberData(nameof(LuminanceData))] public void Gray8_ToScaledVector4(byte input) { // Arrange @@ -53,26 +79,24 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(1, actual.W); } - [Fact] - public void Gray8_FromVector4() + [Theory] + [MemberData(nameof(LuminanceData))] + public void Gray8_FromVector4(byte luminance) { // Arrange Gray8 gray = default; - const int expected = 128; - var vector = new Gray8(expected).ToVector4(); + var vector = new Gray8(luminance).ToVector4(); // Act gray.FromVector4(vector); byte actual = gray.PackedValue; // Assert - Assert.Equal(expected, actual); + Assert.Equal(luminance, actual); } [Theory] - [InlineData(0)] - [InlineData(255)] - [InlineData(30)] + [MemberData(nameof(LuminanceData))] public void Gray8_ToVector4(byte input) { // Arrange @@ -89,12 +113,12 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(1, actual.W); } - [Fact] - public void Gray8_FromRgba32() + [Theory] + [MemberData(nameof(LuminanceData))] + public void Gray8_FromRgba32(byte rgb) { // Arrange Gray8 gray = default; - const byte rgb = 128; byte expected = ImageMaths.Get8BitBT709Luminance(rgb, rgb, rgb); // Act @@ -105,23 +129,123 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } + [Theory] - [InlineData(0)] - [InlineData(255)] - [InlineData(30)] - public void Gray8_ToRgba32(byte input) + [MemberData(nameof(LuminanceData))] + public void Gray8_ToRgba32(byte luminance) { // Arrange - var gray = new Gray8(input); + var gray = new Gray8(luminance); // Act var actual = gray.ToRgba32(); // Assert - Assert.Equal(input, actual.R); - Assert.Equal(input, actual.G); - Assert.Equal(input, actual.B); + Assert.Equal(luminance, actual.R); + Assert.Equal(luminance, actual.G); + Assert.Equal(luminance, actual.B); Assert.Equal(byte.MaxValue, actual.A); } + + public class Rgba32Compatibility + { + // ReSharper disable once MemberHidesStaticFromOuterClass + public static readonly TheoryData LuminanceData = Gray8Tests.LuminanceData; + + [Theory] + [MemberData(nameof(LuminanceData))] + public void Gray8_FromRgba32_IsInverseOf_ToRgba32(byte luminance) + { + var original = new Gray8(luminance); + + Rgba32 rgba = default; + original.ToRgba32(ref rgba); + + Gray8 mirror = default; + mirror.FromRgba32(rgba); + + Assert.Equal(original, mirror); + } + + + [Theory] + [MemberData(nameof(LuminanceData))] + public void Rgba32_ToGray8_IsInverseOf_Gray8_ToRgba32(byte luminance) + { + var original = new Gray8(luminance); + + Rgba32 rgba = default; + original.ToRgba32(ref rgba); + + Gray8 mirror = default; + mirror.FromRgba32(rgba); + + Assert.Equal(original, mirror); + } + + [Theory] + [MemberData(nameof(LuminanceData))] + public void ToVector4_IsRgba32Compatible(byte luminance) + { + var original = new Gray8(luminance); + + Rgba32 rgba = default; + original.ToRgba32(ref rgba); + + var gray8Vector = original.ToVector4(); + var rgbaVector = original.ToVector4(); + + Assert.Equal(gray8Vector, rgbaVector, new ApproximateFloatComparer(1e-5f)); + } + + [Theory] + [MemberData(nameof(LuminanceData))] + public void FromVector4_IsRgba32Compatible(byte luminance) + { + var original = new Gray8(luminance); + + Rgba32 rgba = default; + original.ToRgba32(ref rgba); + + Vector4 rgbaVector = original.ToVector4(); + + Gray8 mirror = default; + mirror.FromVector4(rgbaVector); + + Assert.Equal(original, mirror); + } + + [Theory] + [MemberData(nameof(LuminanceData))] + public void ToScaledVector4_IsRgba32Compatible(byte luminance) + { + var original = new Gray8(luminance); + + Rgba32 rgba = default; + original.ToRgba32(ref rgba); + + Vector4 gray8Vector = original.ToScaledVector4(); + Vector4 rgbaVector = original.ToScaledVector4(); + + Assert.Equal(gray8Vector, rgbaVector, new ApproximateFloatComparer(1e-5f)); + } + + [Theory] + [MemberData(nameof(LuminanceData))] + public void FromScaledVector4_IsRgba32Compatible(byte luminance) + { + var original = new Gray8(luminance); + + Rgba32 rgba = default; + original.ToRgba32(ref rgba); + + Vector4 rgbaVector = original.ToScaledVector4(); + + Gray8 mirror = default; + mirror.FromScaledVector4(rgbaVector); + + Assert.Equal(original, mirror); + } + } } } \ No newline at end of file From ba6ecfead5f345c3109cf2cae1a8b88f3c62a1ab Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 27 Oct 2018 11:36:01 +0100 Subject: [PATCH 244/381] Add issue reference images --- .../Formats/Jpg/JpegDecoderTests.Images.cs | 4 +++- tests/ImageSharp.Tests/TestImages.cs | 2 ++ tests/Images/External | 2 +- .../Input/Jpg/issues/issue750-exif-load.jpg | Bin 0 -> 36885 bytes .../Jpg/issues/issue750-exif-tranform.jpg | Bin 0 -> 5587341 bytes 5 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 tests/Images/Input/Jpg/issues/issue750-exif-load.jpg create mode 100644 tests/Images/Input/Jpg/issues/issue750-exif-tranform.jpg diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs index 6bc559978c..17a0ff2632 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs @@ -26,7 +26,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Issues.ExifDecodeOutOfRange694, TestImages.Jpeg.Issues.InvalidEOI695, TestImages.Jpeg.Issues.ExifResizeOutOfRange696, - TestImages.Jpeg.Issues.InvalidAPP0721 + TestImages.Jpeg.Issues.InvalidAPP0721, + TestImages.Jpeg.Issues.ExifGetString750Load, + TestImages.Jpeg.Issues.ExifGetString750Transform }; public static string[] ProgressiveTestJpegs = diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 758f256345..03f8754854 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -160,6 +160,8 @@ namespace SixLabors.ImageSharp.Tests 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 const string ExifGetString750Transform = "Jpg/issues/issue750-exif-tranform.jpg"; + public const string ExifGetString750Load = "Jpg/issues/issue750-exif-load.jpg"; } public static readonly string[] All = Baseline.All.Concat(Progressive.All).ToArray(); diff --git a/tests/Images/External b/tests/Images/External index ee90e5f322..c6980db777 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit ee90e5f32218027744b5d40058b587cc1047b76f +Subproject commit c6980db777e49d5e526b56cb986001d1a191acdf diff --git a/tests/Images/Input/Jpg/issues/issue750-exif-load.jpg b/tests/Images/Input/Jpg/issues/issue750-exif-load.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4753cd526e8d04f029846a5e0c1218e7136376cb GIT binary patch literal 36885 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

|E-v2hp> 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 v757o=t!4Mz_(u_#&y($VQy(%Em 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 z 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%0D*9JC^-WM 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 z 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%0AebI?|*i}mOu^|x^6+YYD*uW)jG5$os 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

eH!0a+UZneWY@pg|h^60sf9kU`Gw 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 M+%@#es*R?a&pAak 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∓0-n^`wbRMS^kU<_L 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 z zQG(n+++0O8lB1c-K>3QtILP78Rb0sOMoVq{_~+O9*3zjLVkNnK0~s3PJ)pyt z+E>3l`|x@n>sh~MgwE34ERIyMks~V`1ME&|HeB1Z@yyZ)Scz^SjR97ZjjVIYBa9z^ zrCNe@o(TlZ(iogzvj%3!xvnP2j4pb%0VHG7`PJLT zl5LkN0&rEK>z;c4l>m##b1TgejduvwX(gA_(zE6>O>o;Gx`C%vXUR~pt}+iNqYPky zlekw)_)4t^%UhZju!-gl=-x^Z=E9GIx1NWZhUVmpxqO>nCKhpk^O;sW{JW0OFfx5V zolm5zMLfcJ-f~s4%s^QB41Azu9#1*^sgE7H&w(2&p=Op>ZOT;iz$1=wInU`_laa)| z#z%0@vBuXZB4~l~5;e;{I%63e@_vGu7?mxdbdWTYNg#||Hq~F7pPQWEatBU>-nG(L zV^ zwT~UZIUJ5Z3WCe`a0v?{xPBx93fScJ9QDOCtca6s+@fufBvNON=rnD!VI@}>%7c!% z&+F+|W>#&u+^VrJk>%iFvy+_XAdWc4)|q#Flg$?OFgXrHpDSd7Jv$LrBb>_W3L_Q@mP)~+(YLBcH+ z#kh`il6f9eKIs+}jD;NX2|Q#I)4x83nKV+yu&MK;kS6KL%SNgWQ{+4XIRy9P(xx)X zE!IUcvq*kco96ku@_#&gin^1ktg-o_%36)e>$Qe^k?GfgQ|*2K03)K!8S4yzuB4VR zwR$a_bCq2j0`qjj?Sl8_FD#s(H5<#2+*BsKDp*_EyCJn5Lrr9N3tQVY&9)0j? zfN^smKj}VM+}6@<^8Q}imz*4S%_TIXWhKmqNRvZ7ylZbOS{uEFil(RA2w5kjc zI5}W2ILYKyp&?TZtk)*@2+EA=7%=aW02uTb^`_h6f=uM9CGFqkr|*Mm1bPwi0DYqUvulr;dAr_ZIgY&bJDaq# z`J-ba6^b-0p$2%#Cj+1zdizx<;A_ZZb7^>`Sz0TUoW`o$f~>qBz>i9r?(PejOWJNr zh?s&$%2@vZk&1n~%JD3b$ju`%t6J~QPbWC_&!_lTM57s4(#@hEA~MBkc#h^b$Ve_3 zO326M+@KxGMtbqaYFs?RScDR{*^|sH$8<3+c7k}q@<(2|6xj>Ro@%g#{?X;TtAQgo zIpe7q1QI%D+*P}n6`34Nu=z>>X(A_beas~FMPnVzk;`ifCCImR-}Y7y zh3H8uk&N-_RV;7ki_7~!7DhSQC6VqA?;|`OPB3wiQ^yO!vCS0II9X(pX&Mn4#~)xZ z{5j_*yHss-7FJhRl4eEnB$5!y7pcy8AD6GCZB5?cbj^FTiGv4sPa%}z3}miP2d@Ni z^r+93G^J8vn*yF5pbwdgHSi7bP5)r^7{A!F6 z`A{g12_Ef$^CSmyn8!>EaC4lV`5u*2o!Pt}G)Kx-+h{wRY=L~X#DziXeYxj~OQec; zZPUtIiB{lwQk5AD4naBT&!tu}+|Fn7BX^X_a{D>K@87ri>snF3up%LVPaKFm#*^hx zJC?`t71=8&itgaj%)kw+4Dmi&${~WUah~Ag^`$N5Iy{bJMj>8D2MP(~oMhl~c&P(C zcA>2j2(6=Xtq0liJiHtQIpZ99_o@nRE{M7lpp23lCHZ!!@ARyBQ|N06GDg3YPE1kn z5XjrMkPgxL^%TI+PP1K2Aj|`G!^wp>K8HOzepJhakwl2HBzIF_JKDk*=Iltp1mgoe z@k$}Lwrf}~;*v**t6#)(9L)*j9!3`b_V2F~kb8l4X-_AsO7n`i^+-$E{~kN=rf|QOP2^+T5g4E6cVh=8Q*x3lMTMj&t?@ z02+P8!|Y2`9&$qK`_Yw=hhdCxbMI1J-@?$uj{`<7!>y#Rm3EJ)JaRGyarCAkylW(s zv}(U7k=aJ(Amb*k7m7mWX>2wFDYlwuG{@W*DDutatn4~~dHI6#&O21{7iB9Vgl?W= zoPbE<-;U;%Le|X+Ok)bMji|(iXxQ+?43#6O9r2!XP|A|5nU)!&hs$M1q~XGjjmH>a zh91Y7*-Jv>RWF4MF8^k z9Zmsc18Hu&flW^s2%o4V0Ok7h9=wXqy_(s8l2vtNC*?7ZGC(u8f^nSVnvUGud7BXWLKk2&3*a52aOuj5YGQtkY}h0GyZMEP1!1_$N<8KroQ z)1Okj5l3sAaSkox8?EAwFr*CfGt(U~KEAbb)-oYf@`E+T;7}j{eB6FmAFVW?GDH!U zM@Infkgn0_J#qZ&N@ir8F(P?T0ICB57u1|k)L&91XpqeplAcQ7$_mK-jDPyoUof;+ zqD&2uZZ1I>G_!r7Zqa1&npq~1tkxob)omSfft>E+C!jSPR_@|UiRLcb8Jlo9{A)I~ z2Nu$>>sdEi$!#MsXk^@xjN@*9PEA%fk2*00Ts*r{QNd6TJdg9mLgfQZGF&TtrZrY2 zL0&r!z?0vpr`m;@DYnTJj|wm%DHmuXf8&d6jImkn&Jo2HFaMpyygBjy|)eMMbMr!g#1gBdbx zYoZE;3||#NeRy#`&OJX!RIsGY)3?o%avnT@VLNG z008dmlgag}%@wGETS#Gm+`|g(ok3{=9;%0+1p4|6cc|Xt-UZoncM7C)D_wb{hFDZ% z%wvt9635i=c)_I?%*$%U6Xq2+cmn2pwe#K813i=0m_q%^V_GbO(7m^izE?Biu_q#N4I7WvmK^P z9-NMck@$To>J>Ks0Bf^IpL8v;ZlG24JO=O6-l@n*N4RkqkPWF4I9Dy#3JK|q)l0K!>JL1AT=ev*uB4SNfU^r6S5R{@ToWcw%0U2qLCNj! zRfL8(ECg zSuE-#@?(-Ekw8@_;Y&AvbH;zjtleH!xvQJD=B>m5*vTOxc1DgFA#KW|t`zzf$0Pbv zt}ddA7`7uw`#yg$cP>wUFnFk>c+sK^(ix|AXf3i9C5#S0J&5W7$vpZ|3;@rv7-f^p zZPxLW4VV5E3+&(Lj8>78XFQ=aOklQ-*=CKR`&`mySX32lpa2=T@5mgUl~Ev*&WiO2 zV*X&aWzRv>dmQ$yQnz-|EyFxw^BIjMfXD;-kCFiYGEFl|WoTkw-hS^tyv9a4Wl6?Q zY@WEqU39mET}TpFno_<`nUcg4oS)45RYxSM+lKO1NLgkwj0Gg0PEI=hHBm_;4{J8n z*vnroSs=G)Zp@oc+90)+nUwNQ*$BbMV~*V^kcnc2E#BsN$b8&8Fd{}7+ROmP;0YNR z>Uie0Rg=pW^1a(ekhE|{yO@SN4ZDAYw>j;SO;U}cfrKL72@TrqEc3F-8vt^s0RVzI zB=RsZRCPu3M2^}+6|KP&$8RL_Dxr}4+-HG~Fntd^RFNcaBedc}ZsmN4hbpWA%Bk)$ zbI&~0gosHoh2xexC5=4Ch9e@W=rRXExZ@|Ld)0V`E*&2K@3CTQiJN|TB#|(+~SZ4uVMO$~5C0b5$PdPa2k7{hU z@toYxMUiqj%JGckXCw2hTx@pPq>5o9 zkI&1r>m>gGyJ<;QY>uRQ`)AUmj3krY5pfJKTgJXcxdmQk=tAuUbBv#x1B1yR0}5he z8+qle?l4JkRf6@&$m2Qs^{R$zh_2CXr#@B>n+hl^Cp}LcMt@q;FiyvpiKopn^y(pu z2@n^!3L`3^jAtZ+^y3+*W0jQ3ZUWCS+vYs7Gce9ZLC^E_t43)XYBDKgfT}wYnB&hQ zJ+gaM5VD1u8O$?TnK*R7aLvK_{_z7GdK}}eYshB`YAl-Nlg(1F#?r>SVY zI2k;iI|_Whe#VMcwvq$}NZKoHj!OZM&4A60m^}`0)}d{rhs%{;xQYoRe>#Ho=D59+ z677YMVm+l?40rxmsc9Xtqs*_+d<>paEMOljkh$dZo;`Zzh|I9Z=SMsfL-LrSiZ)WM zoDg%|bjCV^>sBI)IO2*6t5_tsh^dvJxe^tSbrHDx!1~l;cer=8MIL)FW^lPH&U^az zq;l1SqS<;0WP5q%i6odvLdIr{E6LR00&*LHpRP03t6fOQ@g%@2I)KN8JPZu`;-p5t zN#n4SONwxXq!+-Imeok6x zs^h$<)Gr&G$Zxc)gcb7t0EB`3Cq4W0r~d$=nIo3n%Se$b#$=SQ&CvADa5=%_HJK)U z%)5SB0|nT41${Bsfm^ngw#F7&n5UZ<+L1;M!bceCpZ>jaP7-(XI%mrWnGGGne&$K7 zF5cZ%{`dliYFEt=vo{xq=wwM|6MPN|+$XGr;_hBlVCoges@uX5i5tY2}HX|8k2aUNLjCUVS)zZ0IS0e42Ei^uK@csryUY;7EGp6s&+Ha7nr4^1gvC_lm#OPk&e}8 zZ7JEI(XQ(yc91N=xC8i!Uf#I%{{R}XER&!S$#1+!skNPk)yO>Y&mDis6$BPvVku%b ztH4%Gw{h(ef;umDQn+lNUN{1g<}C6&a^<2MWE(~|br|&+@BS3|tb(KWm|EC}g`-il z##M~i-ScNS@9Fx~muVbQHN=8+H*6H8!|%!Ik<%F?KE9@w(&9$9l2b8w(p}9OXL67J zzG=;}^dz?>{>KhWV+zW|WD}ln2m|ryN!7X`IW|DhzS$6?F^N}uZ97!^)Ip|^q>Yzw zXo8_K6&puW$8b3wryjLBnf&{;Nx@ks4>**xl1iuFJ$vWt>sl~cm3O&-;s|k#@+fap z^#`XOwKrU*uB0Kp=3TAeM_Af#E+QLrn*%WUP6pN>9Gqu0YTg)BTfFxKtWe0atAUm$ zkmrwIPgBKKmfATdxph*J+(=}2qa>^`=dn2;4^z!t^3jZ{t|W~^8D$s>tL#tt{OGm% znN_Zwip(UB$wm&$A8oj|$Yy3dag4VEf%w%sYpZz;*n5_F5Bjk0j4&r79;2QQHFju) ztR74k5|(eC8T``HM!=k4B^x$E^(9XoDBUb@=R`SB#X)jf_he z3h}g?n91UF)M&usp4tQN#fCU2htMInyWJq~{p(9|hydSSRK@Cj58GAM~)pq?;K zIQOZN5F@v_xDrWu6s6d2R#qU9mjfdQuGaPBaZS4;6s*dBY-1r!sTqq4Cgdepuq?X!L zX`@ntNR)X@a#dU0bs%~QN_v~67u1Q_t=0C#$M=e|fHws!a85_1YDED_;*%Mg)i#M8 zz=c?xWrrb#J$s+dA_VcP#F9qXRgooN%nx(hgVcVtCCqT;q4Q)W4ZQ9u7-RB2nEHBE z-b~I*L9(h%CEPN|1H#2biy+urI6F$`@FVl6B)WECXk*2-yd%rRUQ55eg@vSp zY>HwAFuC>4dHg=LpzzA>8fjM6S(X+na*WK%+?F^5@(3f2{duW5ok+!zq;0%Q9PhP$ z{5=&{-2Rm<#j8UbqcbFcgA<|x3ZA_FRM%jxEs#jEG2HU3XAGe9$r%3tJ*cy}@-F6C z8e51P{cI4;T1=eegV2oh9)rC}lh^+!?Wh)2C0RC8wNjU(92P6K|U<0fX#&V;THvB39~4 ziQ_{8&vL+9MJp(chae#&k^nq%PpviKl1rqXL`cgi%rQz>NPSNOp0!Yexk^!G$?jy# zk+jVs2V6o9RFU5~_rUs^%!cAICiS~2Bvy>W2GgA6fJa|$qxx0I;c2|$kp+lcs;m%? zl(Eh*I*w}Y9rlN>-BLrGQJTM6w>U4%k zj?@F@Rv__=jtT4Olk})!*$lRhkZOYF;Ey`_ua-+FqZ#|r91wSRP;;I~8LMbulH3cA zHd%npp%Y<4XB>vr-+Q)*Mou~aC-f*dIvH1@m zE7vC1iB+R`qWMQVo9X@|(w!PbaIrJJmYTNmozvY%DKj@XRojuA9P%;8 ztyQ?WTV`SB8=|aG?To7A^Tu_@m@xK$yubx5*C6-LsPFWyqZHebJl1FVMvN1ESX5VMbt$VN2m4MUkQGaHfE~l;kz^$OIPK4+Ux6hTXb0~e<$!f) z&&){9bNpGz>6(Sd*xop;D`9gn1Qz0PDbk)hnY^<1a>vPxj*4^8jCCD`Dlrs_w^04I>+H60EyLLP z#yDh~l~-UeNl?rNc=?T5wvgHVvUwIcgREttX-~{?jE`^+@~9w=R*+8-fh}ZA$Zn-8 z<*7XJf_UWPAC_xra!mr8ms3S8O~tCTY_7l`n3|KE-h!BaKes$xITEuL3!$Rj<+{{UW`!8y}{ zh#me}3I6Uf2^i14NfoTFbt0c|0;86eD56PzRpgfE7#w~)`c_e@5 zH9Cm*O!k(~3*OsY6037PwYyrCjBrpkFhec_HZpQgUTXA^L30F=No{cqkIYEY@XCJg zZvOzSRGR)ql1NGy#kN)7A2R2Ij&OU^+TrBVqqCagQ33^NNt+5!BkQ;VdH1fE^4RB< z2iS@@ouWoNkyx@tBNk;U5A?|C>sFWT2FgQi1n=cYJobfih3WO{{&}c8n}ByLUR|^S z6>cSwa>0*44hiYW106kT^ikf+w&Gc$iV?aqZxlfZQPGbW&N$=WG@MhBKF5_^kv-(5 z-E4?oAfuSP%U~`ScdPJr{{XYl9QP)cEjea;Wm%29W)@jeRmybW=dMOL`t&s{kbyEh zsvInZmB_~8pEf-`59RAf(+xsLSbX?`#;nm4!W{SY$j9qisH7xLLroIfC~1PrwgMvD z<+@`dlk7jnt1MHktU+14{pTiFzJ0vsjxo}$!k5M;hBULdEQBggGeSa)mLY-rzypEY zk5g2naI!;a5823xLX~z6w2pbsbBc+==Jb~`H9vJKMyVNLfL%uzKjT#*gA&Q-IdzXD z!Z4(d&(KuL(%#DGfIuKBuFo4r7=7))k%sw57gJT(X9dqdk|5 zsmRWGs9F_0tXqX)k`2CGrR3l=U}QI9N9Fm{Qbdgud!@LEqhh&J^uj4vu(3_bGkLAUotsfdqHjy_rdmS zrD(t-?v*ET$E$JEsjSGQ^9*ju6H7XllkDn#Qlt(}I^Y57MNaI}= z#h^!odBP<>xwyDM7_X_v1N{AJu-o#&^T!fKcPk&gHh93m;PpK5fPR%`+IF{=Ia1wj z+S*l?WSK*RPJk8YRG;r>tz2PqnN?C`PZXqVns2pvZr^7zuys|>-BJhL&p(O9P`H9g z+Tc7z0NaRJNmGuD20b~?(zGVLV#y?Sw(sYt`z@WaDB7U#6-NqvI1~xuc!Rs7BP;4*l~(T!+Fv>5a|noRaoVdj!$99{$8~#(ZhFV^RSJf z!w8QBvHfYb>LQ-x2_u9gE4JcOxjW||WSnC^k6yLgPHt8?>eWpWMv966X(uyoZ}g3- zP-mdWZsR=q(&jm)l^#{vApi#e6>dqvJ&zqd{c34sd1H|bmh#MDWk*YM9D9cg^7>=1 zOw~5>mCH(^A2t+MSiz7hdlQ5AyZRq$x$JVsSrNjIiJo|z**lg;`$^hIQVs}pBlI7o zvt_;)zI&q@#ksBRB0xlky6z`GO#XE1g4XcFScZAns93N{$I~Q^2JSfP$2B6x#e9fK zirrUpB(jE)iR*)mjGlwA;<)9?Sfr6$a-jJv~S z6zpfXM_XIN3(sRWn5`c`1~^g};I|_K&~ULd%PYXsE2_evTm=og9CZU3!c;A9 zJeQI}qG=mdTYGhd4p{Pxp|DRp7Qh7YSMJgi1TgQI!2AfzyIFCbj4}1ds}^n^SkIFj z^F}b)j1htDj2@l(_o!uvxiTgrDI0D{5AcKA(zep()TOB$GOHsAHf))dn+h3$9X~H$ zrCOFnl`rH-=D42lN%o7$t{Ftk-FX;gZ&RF{jB{DX%T<}ek(ls)VS!VS?<995VI&dx zvFB>;UWac3KBuYfYGo$68&#EtyA_T!x3JkWC=o1j7Q=cB@_!%kt5&d0GR<(-)^Woe zOXgjhz_VqE`C~)NE&<6MIL$|LE*9qPitU1AkI5*zm@qtmPZ&IV<2>_9#zk_i4pIwt z@(_I6M_sF)oc{oxYYA16=grDp2i#3+kT_+S%8aXRDzHp59;HYnh6x;FoF8hes?m?M zgxwXn%f!pO%=GKUIvWUX5PathH!EYX zAY|nF^rew^PA-HKT16hv@IE&Kp18^DO-qLT`mAhz@J}$}HOcBvPx5F z-NVRjgrXGlB8Fomd$Gt8GBYUz#ab|#cda5|WfTdK5f;ah$S0s7$aQAi?Z zXe1H{Jd&dAPS$4QDhR>c2PE;-b4*p931(507jAr|#z|rZKVEAbHPRSmA3CbDIyo)1 zvT{AeMB||2IGsF@AC_{nNa~8o37R{383^5lEuF!XXFmS`N~H=kGD_EBk|pypB81Gv zTke1tCye#y>BU2CWkO)z3QoRT2?CaoE>8zNk5A>&rE6a?Uu(+#Q*JLD<}%HXP)2@+ zvm@Fx5cz9wx;_>*Ww+iibI)!u&UiFQ1jQ#JI zxbKlmab&Vv%C9plaw_?Z6n)Wy{(ipnlFK97s&7}Fn{;lA_lKu($f>Z+XEK#OW5*wp z8h?BEx&A}-t<$OC=5+8D~HVzM`uR4a4OZaZS7x`_p<#R|S*QJw9%yv${YI34qW z=yBSb(A_lA1{v*`5f_*o3CctiNW-HXU=xFkkLy*L=69JQA~=knx^UT5QQIB4&-m2h zD}}OarEp@1D#Z=m(isAroP^-*;GO};bIn$cIiZ9p{o)|kD0oj2pJ#aQ6%ed@lO!Bh9+&oE30O=nnXN;Rla3yyx{cBGtECMyIfBo zV6&F};{ttfKAhImhJ&YfB4ISKZxX>Z)Jb+<_i`$*jJGPRazPxCob{+$SfY6rQ*k0n ze|7edp_q<(FB!)?Q>1qDnRcD3cYM3K9rOC}QOhb#5L08QU51qT6KT^$8$zMDd3?Y| z(mq@-IbcUh;Hjk9*X(4~%_W_#BT%84!u{a7N>z;dzVDpZ1 z&MR7VHZq-87?H^cxe;9=g=4%lQJk^kr_!uj%Q4*MA1BL*d5WNXtM^86>(lY|H4KWH ze2VO?ZXL{iT$3z>G3rAuM>xpGV^hf*A~{w$+O39s1v&o!$GAN!bkim^ll2xv1~}Cf zaR6qG6b^j{psKe>kjN%-^Rlda2y&{qJ)%4TdAXJo}o0W{1mC zu{5&86@q{YhAq{B2OuvP;5qw9wJR-T;tT0Cztv9yW3i)tFa?2U> zWSNSU>&U_910Ri7F{ygn+I%&WAe!A2lt0geSVcIpR+O--pmTNTyFMR7oOCDDaal>(iCm6L zh~*^ROAJC_tn$j)PzM{E1COU#j^xDzPK_Xf-YB;;&%&yKocjSxRSxeQQ2z18;QPnQ zdh#*-XlYe*43RLHxdudV6aJ0lRihxT;g0>r1~{sAv0Pk9aCXkA z5(b#Z_j%7kIpdCcaw}N4nbf?KCk+TEkgWTUn=Wv~f;j`8I`i#Jh6a_wxB&qStE?yHJ0foL|eKY=h)2OvGjV8&V zxwb@|)=8dbxL>n0wxleOju^4e%ERUPdCxrY%-3_F%c7uIqb=sPR5NtI#|Msi^sL_@ ze8^_r%J&PkgUU$V>^*tw-;C6f7qt^cr6!8q6<>3#hDPd7r(aGwR}`C!u5`yo=0}*8 z<~idMp?@#TcbS?n!?;Y~V<$N4TdN#yu_dsMX`_xzI}ofFIU|$b)9G1|!6eAiGl*d) zX^=*&LB>V_?UFKkRiv_#D@2m%P_&?c(!>~K9D)Ww&Tx35QmH8HS2f<|d5uD}u}uue zX~Kd_Dfbv1I&n|9v$?tQ;+82Pdr2diVlzBE5P3UJ8A_eNHynf58hwNUd##9xw`7}V zRKxu-o`=8ntIuyVhE%q>-1}tQ8!D^-R~AyDxO-2H`^g?yLu_WAmnFvQ^@bcP;FI)b#2j)F=n|{W(y|@20e~)dwz7-By~jI z?+mg@B9S2s7Ci8MFh@U6O7tN#krrx9wU~c=^T%=LJd5@_h-WDp$(%572h28;!N(*X z)eqnEK5~D2z_voDt9J!mS{qgK<8{kzbSe7W}^G&_M zh^4VhcweHO{d1m}=s5j&wQ*#&@xri6CC$&2t#B9sv9@~=)MK3S&V4zGRHwv>X5w@CfH8zu{7dIir0B#~WTp3OK@B?vh_GEwxKyb92Dt41GJAb?c%` ziw51KHt7J$upPZK%|T@S%RVzJ*8j_25A&P5{^n(?(?8q5^dkTXcy5}34oPanP9<+hpSymg1i5MVN zd&$l)qbDZ=>(kfXhA^_9IG99)s0omH@7F$+B8i=D6h_7Xiqa67Rg4@4IO)`KeSPYo zyB$iYv7T(M1ga$aOCEp_+i~*oj^NQELmWV|$kRM)BQfe*xhKAA=*!D1LJ>nL^B(}S zK0R!91l}REUrYV-5D;@Gpy{aS{N2bFvM9x z=Ld1^&IdlUw(`7}Qp&CpEuT6$KPvryT8yRJ7in+rCuptMz1-66Xxs?oHMfN)NK91aKJ-jf@n5gVT@ z+-=F_q>;(xSFTPndF&59uq0OTTicED#~@GLW1pL_#yV!AxK%r&MFvMBFC5w1*|0_k z{{TN)l$(*wKaAD4fEzSf8Kj5IW{sJE+_@lRbst0R+MF%zm_5bB@<#;DBUivS@u(j$ zVm@G0j({GgrYk;36@pwN+*?A+xJ4AoS(tEl5((#TP7X280GUw4)?h=t7CV^=mOHxi zKDerqk}1KqRnz2v$28W?ZXsFZ4CZ4d;ypbubHJ%qNUjS@DPR@YZrCub+aA8T{{R6` zx0qlTe8oC^qJ6QcP&w=XC!7z%tu3A+MQwpZj>Q$Z;<%pdi%BvzMU2WLXOW~FWDl2d z>-0FP?;n|e8>2Kuz>Zj+LZElxo|*L(v8cxiN?y$-K5TKbTgwb1q!g^QP3!VJo5Fgx!+Wm`>$bisxzIc{tbK{1(Pq?V zmPWmsZb{mpfWVyK05+(}B-g{fGSTJI?_|{DnPs(}X&EGi35-aml#JjK219et&0k;K zw}f=R6>4(cNRV1ijJ8wD%y8h68b!e%af7!c4td5a!2C%Tn}6ekTj*?TbUW9QOSr5z zIy7Neua;Qla@hHfPBX!;hgXaod2D|`Wo_Vb?yNbIlG}7`cq-~0O33M-@R3^Rw<_xX zT$bizb0|&0cJa6!xFw&-0{fnEAyX7 z@zZGfzNe?@w$LPco!Tdu_R+IPZx_r}8Nn;N7%ZPL&NIocvpx;{PST{(HTBgEt+e`; z(>1Huq=MQTes-Y@OJ#F{a&kc;qCWja6X&?1ompWWNVj{P{)zCjR=lv)d`YC@QDD=3 zrc_h9MJz$*k&qY+4mx_*m+3l%&6V0q1?Z09buzb*UB)DhnRrHFgPddXJu81n_@}M- za?e<|u<<~%TZrUYW6~MpXzj_sR>;6s86QA;SCHB2y5notM%qn2_9^F*Z?wi5Ws*Wb zSoUKKMpzS`NaLuk{{Ukc#dkbRCNB`%=GxtNKC$?1;_X6z6GNyhiv`j}B9yj`R2E!? z!mb7nQhM{yn)VB?i2C)`OX-sh3dEYE?o}xwPbZn)8QO`Yyug>coTf|l# zB)xqUUfSD40<$m?x0b+%3xkk8y^bs1`~Y?RYsD6DNqY^o)Z#XZ>UbH^Ne3C^6N~|X zYsJMpL=#-vTHJV5XTc`h|MneFuWpe^P|#|T2HCk#L%+Zpt) z(?5hBGQEhdf#N+m^!--SIMiF+NYTc~<0w@)AmHR+^MS`){y=HB7g~?RD=T^K*|h5h zXzng_`-Y87i?of6$smGx&+D9h8D-+_drk3_PiuJ|p$urd@pjOvsQHpL-Hq4>1+orD z8KVn}qn6e7i8j+Q;%uuAo#2%jyWL;6q5A^`+G-Xd*`{d`@f#|Tp*xa&vHF_am(N(( z2qM`GE10K`XxogdV~qAW_2l)hp8gknO1IWyXeE%tByhyhHN2!p8xV55jF3J3L9cm9 z*7_MHEh%9WZjmP3WMl1*uX_DgEXPAIpr;Mb<=odQuax4QDvNE47dFc$nIaJ(eW4o! z1vwd{@(rWC#@mT4smvGP^_R?YyoVo}Rx-x^p^9ZyQT)8r@XQ3$n?$ zpHa`RBBMz{+TS0Uwv)L4;K)h)r#$xLe@ckYC9JlQJF$)7GfWixrI&@s_2l*bwB;)z zp!tm%-Ch`@X#758>UenFse3=2S7Q;Uth+mM3PEmo!O&= z$k}0%%6k01-{DgvS7@lvLp;%!jh5k2dMR|(@iY}%dVt0?u|4j%XwX#XQtTKADI~)v)Zi9DoJkcEep5I5vB*B?w}mx z9(m)Z6xifg)upqAr&!nbp?+U2vCk(RGm4$&3L$BvD=RAg?TI@_aZ^@SE_|Sp3rM53 z-hNQcETs-gp1l4&DkjsdUEgc1$LeE5}jMml`CAT~M1Pu8r=qD5mQYF1IT6(2cW z*vTD12eIq{?^SK#jJKRxXv8u|u_CCkfOxL_lqGI z&m7~7`VYsL?UE&yIJPo*v8k3#`-5QQ4150oUwTPl!1E=vSHby=cOpQooOK*^ro}zP zlQe!~NgPvx1L1JKynA}rWf&SYp?N|J*zTYR7^5&}jaf@)k8{F-CmoRKvN^R4(p)deY}fgi#Z~*Ad2+&Zi%{l3b8OcL4o( z;-nC`b=+HWM}sO2pr|}?>Uj62+(8uYh}q6c2x?)CQ8-(1-#Qy*;m0sbm4%`Tgg&BjW$;bGL!d6U4>8{0(HY<}RGa{|4GdNNi zK|6Wwy}v(tfuu`qv4zg(jb)Q*k(3jTI`QvLTS#rMBaxm-Bz0|zyp7y*k;jQU{Y zV>}wsvK*X;dBrD@#9>5{Vo*qC&tCmG^#1_sRfr}Nz|IQ!O5Zq+LRb)ROJk=zVyds1 zD`rU)q|&#SIk6V)w4O4VI5_LiP=1v>^IZjw8KY=?(4sUf3n&Kz@FZjd&myy^oT4Qc z*lAeHym8AK`Gs~7Cga~D>sDQK^=Tr$n7mU)V~!hJgB;89_B}>@M@&=K?D9n^7U8_M zK7GMJvoisJa6NkG+M@FX$Rrm?ml^p6;@tN+=shcjqH&jzue6e}S_1?tdy9xJBN#U7 zgpwF_2Ox3}9C~%DX652G%#leVxjSKwFj_}F0OWkx#aFo&bJ@pt4a~B-lF~(YY-682 zI%B3e=bk!LF->VJV))G)6b1x_At7eY21j6j`t(K)MMk7sFW*kGX~`t5dnCy)NFkoV zRd#Y)51zRrfsxNzWO{&fh9(IIn>YpVe|I0Jem(iAWVgg3X)R`gCRSMGWZJEdPTXhp zA4<<93gMt!perK*#@zbjkF7bBt-zsFv+>)<>U>rXwL&uK@nJ zJpNS-TT<8e$r~avnB>OREu4?UU>cagq+BkG4Gd8WlCIAxAlwQ0iOzFTh%NR!!Wbh* zMm}RoAqvBsll)&O#yxTLsbY?KP)`DRsU!~0g|G@K>csF5U^wb9GHUY8CT*sI2wY}A z-N*q74_=_>1Gj(1pEFN$PGn?xD=?WRf={$6{F8|avV+(jFbTo+;8mN14-E4Ve$(Zu zh~seIHvM=_IRk13aI`r}CpOBd^a4 z$IC}2?=qf8)O%J-MC;{C5}Shii$u9?t=rU|wAGoMYTcJ)@*zG_10)LDqi0YgE1zuR zIO*?0BvVe7*0$`y9hVS0GfUs6u6X0H^(LQbC5u5Lw)Bye_e^6~V89Xp1%^R5&p%3} zXO2ji#F7=ci*8DoN~s4vg-`4GS4=LJ$3l~R3GR!@ETtz)K@_Syji+-)df9{Kz_ z)s=z^o$$`mrN9N0QR>sY}X9_RMRq< zq~{9VIqrDxic1?voxamD+syIq@{G|21-SYgduQoP`z6PcZQYe147=FimQ&9MsQfD0 z!~{k)P0=wKXu}+O6Z#MT09`BcoXVYtOEe2T;J#~&~#nf?*nj(eW#+vaB?0-Hzs>9gDYY>Dv6a-Pmflf4cH=+i=~Wor8pT{$ zV~W`WTyOceENcpd3%R)ClYlt-^T6V!^6n#w3HE{Jx011j8$@gKf1G;Of7%l}Z_KZZ zZBdZKp8o)-tyqktnIv`JOux-(nKBuo8vFq(t z?q!t5kXb=#6rv_&SsQF|sLxEENbCvZ;B_LUyJ(U^suFeK+Esr)IVZk42DRCEf> z3`2mVWMerv9gcsUR3#*JB(JfZa)8{f`^#(3k~V45+sh!6^5r?&!@q2Uf@<}|5n5bC z>`KJJu-nLHZccHYr`yu1O6wEFaI!3gr1|1xVoBuW=Zdyrmg(K(W!vO4C}LD8UtIqH zD%v#^nXBA%Hqo+uoQEdobi09L?sCUGjPO5BDa`1|a~u~D3x!24tVrPe#~9=vO!W7~ zR)X)#w+>*LHYmib*o=ZtZ1o+^Ju2czQV3%RjQQM90;30~=xap;*^HIhHKZ$ik82IJ z%$IPc=~-hestF(k!6f5?N%a79sAGoQMzT8=4&SlM; zw8)0pF(dAZId;y>0^^M2Wb!fGRPaS*=^z}7rbdK5N zwSaFo5vi2O18qIA$LmuIy>4#_>A3?!w-YqO z2XPmaT4|M)WL6%dwn)M6&lP4#jhZY^7V)`SIbteHC_VA~jaIj7Yn!QISq8=o{zB(? zJ%?e8lir-C%FJf3BJA@=BuJ8Z*6(zGc6^3qRvx4b562mz;jgY`e=tdS>V;*xnm|Eg z&(}Tw02+oki$OA^vcn(Rf%43UY>YA#mFRE@=j-cGd7Dn6%Pi|_`=hTtgH3^dvMjt3+ZN6dTfuH1h)%d|_ zB9b>VTsip_zHBe2=bFtML1mG1Ad~0Vgee*5I`TiyTI%L#>WpJ^O48g+H%St}9%tSF z49vjbHyH#G)7u#U=BGBkR#aUVebO|n{F0}y_*PHMg;y@eV8o0v)k4%`8 zD@lR9cN~cTQ;~s#>Os#Vui?j9ZcN+SL3JmEWFamkXK0WNMJ7P<^Vhx&M)H{LWQ4v{ zLRm~i5~P!ij<_{!k#Qtel18)J!Vj6{UI^rExya-mf6gk5u@|+xUoJQ!Ozj-`jKl&r zF+F>JT`LtEo@Hsa!WL;Q+Dog8RWZh6g^~qL*#m+{EWmd@{_x(YE;z zERCLe1~|rlAb$$WT{c~cq!%*IyO6OXc<6rvTPYM!soyQ+Q^JRJ&A!G~9++d)9{o8U zmA6sGT+!TQl7);U@k-XL`y5OMnYfdKgggV+j)NJ+R$nm$L+r~WX}MsunV3dY@tmm* zmFfpVdhx|twy|B1Ta8G_i?@B{+7&FPxd^A8dkl4`2$nA>q=_sNG@esL*;2}Idvyo3 zYZQ=FO4=0W-7}<67bxx;Shr(rgCGD0QG$B<)RyE3Sy5RQ+!m5Pc7@O0_UDhroA!q{ zS4{}=k=3^`1Z`hm{=HaBapW0hEL5C>7%h?CG^I11E1E;R$PKHyNMUHM7v^BQi6cJw z7~ql9>rurkB9};5{_pq8lZHJ`Gf=b?o%bVEkN?N7ksX=2T=QOJW@KEhJuf1gs5h=1 za$VsXm6>r}?zLrKe*?-&g=DjJ{~$Y^7q`?Sa6Tx zO^bAAPF9h__N{0{rt24u#!jYF%9V_tecb&AWJ9bQqRykjV`{=nq`LJKjT3LhXaT`z zs&__7%rs$V)5d|5w9CM+_)W&-^5qd=(j}gvb(ec8z>q9Jt)5EX+4tfN@)oo>b4l8& z;x90~nl>~UA|;V^#HB0a(k0XUxNO|=)U)w4_Zl;3Zr;vP-0}_ zYJK;aNPnw?Q*Bh-AZ3~1JXLh)^j!W!O>%kr@Rpv;<7aq>>}_u|xv}FkT1{i1-}Tha zt(jbr)$JV*w<&EZ%>l;_e>E$*Cau{X3DXHdt27D|;~^k1Dhte8P!$iOqS z5KJ>G-!N8`X@(;FUUjRB5l?6oaY!N|#BQc(695gcA3l#8-)Qfc0=GIYKK}-;Ao|gER^4ffb+n z*pb*Fv-^|k18{3O(O7A9Sy6f+b(%efeWZHGFdNpWK21Ixy+Jz&vR2u_&BtYV1r}=^ zg=F=5a&?KsuVo_EOlPS>spQea&Y%S;-FqW%&&8YKZ&Ms?mDtNLXMS@Z5F z54y=eiSPf zp70Qzr+-@3mJ7Bg5!A8;WJe6SNilg99{ASu3As^2kJF_o0QD~Qb<8)3@2Hsb^ryV> zxc>oW2kua_yg)dpD8$z(kyO{VKR1o=!^N_t2B;Vp%A|EigxY9Rj3QEp7kRj>P_Avat#?mGFYDF3B^-Du1&+8uQ2g4c3hW$u z%4SVlZ@`z8-WE1u9VF|1>!In_(1S7H?qZEr30Gldqo>?c_ovX0x4+Li=L~vg`D>r| z5gzwix%WEObd`o8+PpIkjTl>zc+|+I8LioUbqyjUJHmrwix@fl8u(A)@W3={3C!+P zoC?Xj)J*KZHe7E+VRBo#1>p!m`{lB_>vAntqm$OSe8g{gD(5u0RAbu|tSFoQJ-O!O zcq#g|m_FL{XgaY9?&JGekbghU`UGpVV$;mkRmjz=WBq=#(8IY zm0}Eu6V+uk%vxSOO6>O|{g5N@!N;~@zSLF7-M?q}Y;K(UsZE;F&heBw>ZN+vMZM?I z_(*-O+4_Rg4=3$AH@i9z3>P@JKkxArO~7YAQ=rjv8U9Sgcb(%iohy z9;p&Ffwxxf?ydX@ThR1KjBCYBw2n553r6m#Vp(8JRH+X+Ha~w<2V5+C;)BKr_gc7FGKjfSpNsU5Ajw_GzL#p(mq+?B3(YQ0sqD&0yLJZc3R`an$ zf&;&mLOWqRhMW3U*M4Ne-tRx347*$;SKoosxN9~fZ2zVd?=8L3=6ob> z9{*yR1FknGA$_w)-s8U}KLb0-PWO&_I5p-P6vh(vtaq-oW##SXbS(l>%V3*2YK-rH zfN7tgtd=E+-)?QX8IAOUtLfG%#dMo4UmMAC0?cM)n&m4ggTnoU-Ya?HFESQ6F;_P< zd0tVdnQ1qHIg&EkN6mjzPpz|D7wS*3KSJc^GZj{>mwR?9v>(2{(Vf;qx!v;5@N%c6 z*3tp;vW-a3S&F$}eJ{t$h9rn&Ak<~m)ji6T6+G5{dK9Zp`z}7|Vl&|PUyZH~D}-LX z^WGE4p>F>nH8bedA3NK8^jOQ4g8G&b;l0A1!#9`KB4WZ6Mrczsjxd#Le!M>dI(b`zer3hdlT+Y_?-pfo4} zLb|xF$8QFEuoL4|C_Zn>)*>$U(SHhmZvJrWy;b7=HnTMDvE`&_SbBQ;*tf{)-l@}8 zj3Aq0-wFq^assqPwcbWbFwCw7v5C{?eMW~cy`EYSGE?Ob-@+`6Z8z)1U9|@DzJxlX zR-$En?sdJ4;h=cT?KkA|fUhb4Cx73GwVO03xwlCxR_~D2xuy{PO#w$}szh4o23_KU zs&8&+9#d>;#MYZ3&822a^_9Qtd{HAe6{BqY@aJFkf@c*MPNUmr2I;-?v_D0Cg5A0y z_1t&yMB%m`+#!0xzS(UX=E+%y%DPrtaihJ4^k3n6xb{Yl2YDVBR+*+i5WO9wgq4w8(Vl{Qjc62U*eg{3}p&$m5&d&ZQ_3L$#jnrzo9J*7gWYVX}&q0A9sp{@>K zO2z{d2u&*2nev&;i(7&Ecc4N#H3;&<3V!{p_qN=~ws(&_oD}+5D-je=Np#x+f_@#7 zzuv1YS}rY3xbMCs&K>~)Me{|wM&J6Rih&N)ol>i5;n!ql(>~&0sdIjYGz1a_imO z260#TJNCh-b}nDP4RCMt*S{ME^CR;|F0!j-4drL@3hDDOHUqfWAKOT?T$>NtM|jiy zNhQ{nIE#6*s_CDEwsgL*iBxGSC@N3oGmZT;A8kF0*!+R*u8HFlj3DlNM`P6arU3?1 zqXGrw|Ge?O%}i@#_4|WsZ{Dd%vQ!3^A7vB5K2;@-V&!XxG{YsAo2!NlcYX~-Ba7y0 zSBRoR2aslZ#OmDRa#7#iERf4P!#Z1U!OpaMe&q9nQtr&ikY^QNYFIZccWtAYwaeim zvfW*xn6;mq7LdP7tFBSr{z|&-b2rLw-&SA6Z~QNE(gK#tf%Ku6D z`e&YPNAv@irTOhYx=r?1CtX&B?_b6DX)OF)fM`ps+`otH=FB%RVp0WY{n;vdXl0>f z31{wNf0{aGBb2?%6rA;Vx8iXdoYWpeB)=lMF%rW9H1MAEV@%K%r^v#J4RD7s2(rSK z1ta|2#hG#$o%9}WUv6J}`a0K#UKvI_DAU*}Tnv^{JN@mA@bJU~9%6^-@SvzrIa##2G0E-^0#H&<%ft)zy+$5%w`ejo}{wUF} z5CFTtng@~P&*Y43EzgRY4LN*DW3ViNfq-L&X*4M0Hdjf^ZQ==&JH<5Q4||`$!`JQO zm$x_bxL2#kIX^cPu{Et$n^T|6oL%w+a2=w88t%ml^~m)abDH~Abbdn} zw%(pKEgXT1Ij{tpNQJQL^VN?|=i&U_<=vbmL0JG0X=~5ng}0rzaH6LhD8qn(R{b5z zJ4XkH!-e~-7GgHOa@<>clg|cX%~GE+y-;*bzHoyK_vYGXS&WIDPMeoWean{1y=cY< z5+Di!50QyHbYEA;i5Tl>4uHJ5RsR9uE8MrpN5XMBd6L4lHT&rlt%S~5OjJ?Dvw78QbO-mF=fhxI+h^eZO4F(yJ1tG%a;~Dbcl(#D_o%ii`38)N)cYP*Y^+ zB1@YTeu&G3x!@_40!!Z7m^X`Qdnj$?)(py0E-2M4UNO^gn=vN+;M)s^)|pFRkMXkY z&^+jCzbe;nD-rFxXWUyF70VSJ@kY)%2aqOrQ#|Ge%cs*TZxY0cvC}i40eFje+MHJE z-ps6&hC0O-6=>Pt)6OHUq8+?NBeFa+v&qC*Zg{RSTz&{o&t@BMG)}|NH^h|OdNf5| z2-1Rn?dDCm7u0Wmuov=jX}b}N%!Odmqv6*_0jj~Ij|uhn-w~xr#d;pLx~(d>rjczJ z{~#@x&*vAumDR~OTYhNRZ7h-K9ur`_Rh(R3$7SYO0_b^prp0jg>IAo@kH@J!IX3k_06!tgz}xwB zeafEaD_HGoA%!4A7#A&wjaie2Pv5l=#|a}q`~mGs`qA9Xu|*FeCBzTc?W{dqm=|q7 zZ*vE4U~WYc6s1eg#{D(s{hLg9K&565HmNF>Xu+@Zp#o6!|Lf38rXOcevqwmKVC?k;O2?MNo@ao?-0btI}~VDkfI%}=Xuq0_3<^;=Y%T%zysav?92Kjd z!ofksU{6ta{VOJKN4Lip&%JAZ^n7ljU5pVFD)e$K)oNvLy+A#`NhQ^5l)<4RVhM~1 z`?J%+Jprq9@TcM4dXnk%cLTGf&eG;Rcn<|*8I<}#hNU#(D|D%^l$cS1Q3 zaePWmP_YKe?mZod%8*GiWAxN}O9BY2L?EgqXkLHVKCrVj2_9HUPVBdFIe+~^q&e&* z3+&l$65Re>?WEeN3qwk0N*&pv$jwKi(N+X`y)3ThwW*!ykO+{Gm!%++JgD~8+mIbP zh&!d`usidJ?Pn=Vwi|5Rtlyb$n)3)pVwG<_f=ct1&TG|)WtnL`rZ*Uc9Fmn~|8;s5 zYdnZ}>&<3*R`fs?ttcBxc6kT4rwB7dB!_bLcINO?lG3AA6vr$dz7|(XSk{E*OJwLF zdYR%$f97SRvK$bPMiB#<4uDI0e!8pbC+KAr$X`7Vr~ngla6W(T=n=FEVk@eWD_l_Y zJ2!xnoIRNGv1{@2QPy)6F?c|mo8I~U`=7u61E{|EoVRG{8qdD_-aTmFkUKHmr2)FaGS5O0 zBbB2!150;Yy^n02?3yP^R8U3B8k#@s5JIw7ox;*n6`lNDD+=YJRhbPd-r0nf${R!s z+erl1w9i=ks{oHN|GWw~>jrNwxmJ@r<;4a4xc8=^FlSpCY59HgJpF{S)odmsLRLhq zn+q-q6RCRk&wI`QjJ<;=t%`i?9wkTYw0r~U1<4AgD`t6UDJz`PByFYG!{GF@K(@eR z1C`NVW$l=?k~{ncABh$!?qcK;i}~Y73DeQt$a75XKF=_0Z3N)vYR2pcBmnz2P*`&% zvG!ai5u$H8wS#MtqTG?Cd}$OWx|BZ@O8eeB+XAgWXK=b>`)CrY^rz_Q^}G90FFYb@ z-#-VeWxK>_Ht-jy*$kNEvWr*A18tHLwZHJRsEy76bSb7Ezx!RTE!?EQn2{(58I$@F z#N7KMwDRVM+;*ig8%GjBDN zhNFyHc%_OJ?;;^}FL6e?QixfW3-}nJt9nOSnO|#g65w$Y9Jl($ZTHRCcTE}Z+e9`3 z#ND(K_&`uC*`qvdWol-$*&hk^f95)z!$xAkn;bUMMG=JOZK*o>Cc5RvKfjyxFZn718-dfv}yfCy{>SWw*JyJ?T z#$c$Tp&XSHB15zAPN}pVadwKB@LkbzFQc>e>=&?Hkq|_DI=8@MN&Dd%AMfv*1iCEy zvcVCG?TBqC;t;Dah28@ENveOm_~n9LwM!oDZ#q1kqmV`i!~A(+>^I;##~V1oQ2`c% zDT@_Gs%*`@X~)x>?tz6oD0H*|wtyhm7LWizeOjy=6AJXPch6+zeL}0-cB%yk`X?d3 z6#uBEGpF$@0LEgDI{5Mq+PjiAQ`^i|(~3x|8SC4n64NZO>$pjA>iSpjx%U}0Zg}VB z%a^*(7~oqsG1yEQZ|+X<+nkhSv25SyIHOt?Sv|60u9^K#_8!it5o(_^)aM^iY*zQB z6WGUbS@z{61o7^Yo3S%!jOy)qx!{B5!4D_`xAkg>EEB2_O`c0FcN8$tumqgm%$U59 zHKnOYM)cBNraE+Ayv0$Wl&#lE5|5F$Zln?f1sZ5y>8sjrcbF^PKLw9ggXxscR$0ug zW~^ku-QE#x88_BL?tt!`*C2cEgBcBm--=6$4kvN}nCu~AU=VUXW?GlPUtR>ku+}M+ z%6G1LKT}HtOKI=Nq+{3&(3>>|O?{#k)FB2&grj;2f!=St(NJ3INa&=ZtCVZ5e||06 zuGNjHmQXcKeJhMPM{LGUcnJr?r2Uc|MA8$NY&lW2vVXco@F}=A|nM(obP* ziMrC;xb9u>s!khZdy}+gPp6Yo{e~aFA2U}L-Yc8^&%?%SGFR|yjQ`clED>j6JS5cL zCvhlIRA}HU&b@_sQ8ZOfx%`z);oPL>S+E3n_ERA$(w|on&bv~`m2@bV^D1!TQqTU zUTi=7TG0o{v%YiZvGC*ny1Jq)pJ!$d5a`FLmE|6eajS`uxmQc+@qD3tAEwLPjm~E# zR9kUUR;5oEmFyWM?>6` zp)#GkJ-5QKWTmBnGAAeAhZ#PWi`uRVCE_e~q6A?2e0pDk3ca+J*bdW6YU?K9R zO|Izckfoh~%Kri0doeUuPBELqJX1#sfT6q5qL?Y!3IE3OJ&ydit(n4#j<1fBN*H$c zr#-%&X$4m;j zlv&f`Wz9zX70dO5PZ?Geo0g~CMMQi9I!DM^GDQO;83f)S$w10Q$mTLN*ih^P=!e{5 zEtSM%NATCqrwJ|zk5w#Dt-JaE48uM?kxoDv5pM?S6DdgMtIcH}d(t-Lg9{DlU|XpN zc7p%b8vE1LR{nV}GpjlW|GKKC^$u?J;qmZrRn{cFAx9kk`E(1K5Z}DAmFAEHudNL4 z7=oNPfY!JcDJ|*gbxwxEn;Py-4+Cda$@>dBD8kQ^6A;S+W4OqHuWTxT&yv>Jh5ngV; z*^{(5b#vahZLzw(%nw;At~HUHgL^QN|g)leTfA% zhNpLC8eQ6C90M_tDz#f+6O_M|uiOa12bAR+R(Rc3%ekyv`Y|~>Er#;?hk~U0$iM0v zQo#m-ag?j%Ev>1mhu6$4z{c5W)`&UqY7)JZKB<)A_k?5&e7}CGod4zp^Ov61UFboY z8qZ`N(8J5kXzM0r#3z0PmC%&35{n97cYsFQC%&7m=>{3|13W4_mj2RH=cWRgYV4og z3MmdIh1ZAX&H6K~unB<`pE?Co4@^U|cCCVOrAc45?bdKRw^YC#sH-X--W$rchl*|0 zm%88A(FpL^n!)Us^yxD3x%=N$<|`ugd$U5?^SBiyYgXVMZ2HvIH6UMwm?*+U7Zg^A zF0%(G&XEtoYn$1{^2-dJGXz z0vYK$X+1T@t)5K={uMu$n4+r{?8@8nT&jC}A2Thymfvz$w~;JS#vOiAwB6aLy`?YR z^`C?@m1GBMLMf1i8pEP(xzez#r$B$&?-+q=8g#w@3)hycjHc_WAa3V#3n9~gZv4G| z_D)5S3Oc?Wf_u0RtOvVC&$%utTMjfE%x#scZGi>PeR2!ehUQJArrQ-rZwIQ|!;xn) z^3N-lE2W9PuJj@H~Aw&ZuN)iT(hAVeqZGDu_!rj%bJlUgG!10!Q$lE_^Upw zYVDiLchbX6OBgAjCuXSBnc~Y2MQ_-U+;D3bZYW@=NCDBYWg}AXSXZRV!^LBg$;x27 z{!LT|SjhfY|89emji!o`u&5ID_c#$8=-`65x??U91}gM^VAs@ZvlRA6GWPUibdQ3P z89=l~+ePk6z_)Fn@wCErdwt|tN1?<*Y6!$&-^;-Ttu!cind$b;nz=W?EV65-1pOb{ zy6cRgdxF%H(oaqo%VnyF6@?uoTPV*hN>4ncdMyf}qfV-bw%&RR3tO~W)rYkhzTdo= z`Zq&of>#2W%}0eAK@;X$sZ8XO8F}<->zV>rx_`)r?Q%ZcT=yi_F^>dEIY5|(o5Rko zLu*&RR$;R0$Wm9ei5(NgsZaT?Dqp=E>;-vqHfSt+k>5~r4I_gS5Iy0d>3_sPxd*dp z&k-0@Od9#ZyjW?1fD8z%$0ZbB5{NKm0g3b7dh?2Rc2Rym|0epiuSwS+S(armbK+un zN323V^B`3l%HJ3n&T~7kyPu(UF);0K)@LnS8^p+tSarTL^N@0#W%QQ^DQq?gAC_+; zJCQwJVihm6?cCb1r&>(AD3iZA1KY{`NpfSq`Y+1$0g2;B3-w~&3@h6A3|OS6Xedt| zjHodee_Xp=NwY{h?)DL*op|vdW3p#TBg))ocv@u9e+_kPE0^JJd7)*w+aC6tI`5sR zL6q?8-i-x(ZL!1HtMAQ%l>3TOb*&fEh~+nJ8UcUFzDa6Jp&;IOtElYvu-S=Nyy8J7sB8UKoKib<=bp9cS7NHn{%Q&4Y@ zL*%hjD|D)TNZ|C~-jDn+@D~1Jb}7c?Yx0E6S}Qg@GQj*&@gDNtC#G4E%FfQ_T>azM z@%H_YO2|t_=O9uVV4AYU|K^a2{R0RUql;%E% z=iYN69%=lCg$iTbAm`_tMJRSBcCTsSOxrI_uY(o#p>^n86Z1CHS{`vQ|HHww%BB7( zb%j46)vS+K>4R4s{uQ3H)p2A8)Q(RSW#-Cj+a9zQzB*mfIdp1!K6FZe9P-u9p>2PR z)XvL_ATVT)u^=TmepnT9E2m@2Pn_(9noeO%>sV+5Z67AHwQ)TK46{v67-kke^zNmV zQM9^_TEZq=V=8&aMDRujh>iZwxkjc;&aNNLrKqUA2NQ0z)Uc7#;ZGEHHwi0FReNVE z*j+N-l=E@d?&)SjrUUst5I-u^%o}x8O)tV9fbea)?~n4GZMQWId}w-d7)793nA>g^ zRcMhix!H@6&QsUfv={dF<)_z^t4(^bT`UtKGiN{#I-7zf?d&{SJfN2K&3%1nsXT#; zHdmjb0UY;LdgRD?!pVbDAezd1U-e@0KCmN+iiayLU(Ud#&HA}LxbdQ1Ql)Xn{H>+V zdtG^{SmWfbg3+gU^O09#WL%zANu_8<9PySZY8aSB~pw=4>#xu42QIrk#RV@Id^Hn3}b8viC0 zWscyKPc)U?{IXKUJe&|HrXSiWR25X}_wT&-aB`|QL2(i%)&G6$mzf11vUIbchoAC6 zyDMkD2I@($cWIN0sL{1Ag}=AXD#2KjZ}w*2aph)i2r>X%|7OS1R;P4egTz-?S~X2@ z%<=D!oqv1sP>#Xc5aYQ-H!WCk1%%B3PAGe_+&$HK_esT@0=!zTurw$#7E?3EM^6yj z_emsP7$4s`CE+qTaIJtB37+f4;or(aUE{ea1@ZD@(90!r$T>AX`M`^E8drL*7kI`# zIy)RF&9hyWal$_^&ZDz5UB&%P&9dxj@%S0LZ)R<$xhrcpzEZ#9%ssy}*@3*0 zBR@x#1WA!vnqO`H2MB-q0S%9(^~K;ZS*rmmQ!lc2Z5?cBf?mdDZnG&E5NjX>G=_p{ zy>926nQfL^6RZhuWgI88<7mY&FACcV9@@G+a>(;JfwQ5FzBhGwjZQzld|MV;Uy?kA zd*jVQ#0f}i_4oM~U3X_l!Tp;cHN3F5?l#nHEH1yT(}%l6xYD`H;vTBF{?|Q(EiibY zI-+bT7ZaE+IZ>@Qu<3BM$2yy(XG-I)nfkDSw{G>~J}>cvj`R6cV09^~Z?EWe<9;{)bFPH~Gjqth#br9`;hYpB#F($3D;De-~O`1NK_U!G1P6 zc+W0-%b1Ap5V2`Q_HSU3dA@;gvD_W*&*NRF4}srl#rWfMciFAujTtpFMg0Mj)(zR(cGgdV64?(ODPh&!x~YL51yO_UT@Jljz~_02m@K z^P{>Gx*ypxtUz?@b`h1%{P-#xKQ8yPM(OWO%zs|?x>?JMDN34iR#UC;h&#j!iRza%^%Kj zf^y4NB)hed0iS{|y=y$y=lq>BCI_`7suo|WF~ruvoR&T(6!2P@7f2Ur7x}XIe{^c{HU316SsiGa;(|IS=2{UY zJ3*MD2k3)6D=sxVzoG&dE&(qBA>m#Is6_{=Atx=-bI(wc^4rQf^_{-YNWTPhA4=5u zLe8WjCU9)EcXGUeW^{mjW+TuppLoq@zB%D;J$RPN>NMnmq^ZOCMiKcG^3NM@d_Hr7 zHIYPKNgJBqWs{wzZFp>GoTMDBj}uK*IF_3RT0(y@sT{2G^pJAr(EiU&uNt$c7}P)T zqw5{+hLSAOvq+Bh5LZ_xN#ok#G@0)~kg${Khk-)Lx3i+&$bqE?%>#gW24VqL{mYSR zRH?@G=1U7`zn+QQur8*-1x!HLweF83`vT*Z2`L=j4*h@;^uvgc<=qn0@bh|Ou*TnXaTfE^hD7Cj%Apy5hnFslR(su1WzA!6k{prF_ zOv;cqerMKIP(GtR@SZu^CS-iy4X?5=0^qf2anQfhQaFc+?F~=RGo8I`DUB+zG41l7 z7$ZQxMfQ+u#_NtS?1_W|kjtpCKgW}|ORAH=M={FjWB&|T!mhz1nM-m}?6*0itT$R6 zy19x~SPe@Oiw;Gc=B>W=eiYF~C#vM@xqXPso7HZ8Xv=dn;eVq>jtNE}#wEq?(!!$p z`>xb1OX+3}cawAKiwo@Ba!xUBo)wQj6o!W&99xY(BP4QA@{+7=T|bX4TgPDMWESie z4q@0f(0oB-2vafu0A7UdyyA+UWHXTpK0g`e=+T(^zIgQGvfutR6qd%~`7cjO+nMIE)5|+ujDKktKNwCQ=Eb0+Ot3k!B>@?Z)K3DmmvbaSf`QpaZ?LDpqs=O zQ`TRc0yuG`aC2K%+(RH0ldO6UNY-62n&s0R9x9ZH@P252#;8afimnmdxO0A-p1N&O za=A#(qrv5eqXfi#e^ULZw!}*e$9IH(QGbN+j1h2O6SNV(vR66ZK;=K%Y1zaGr^}n- zn2s{tBd)7D4cfAone{vE|^dPek~pnR{fLxyv{+W#+xuY=An7nkpf{?`g9{;yTfS_`fz z0V)``d*b#o(1-xM_w@FiAF4g_Lx_OV)S)l|8HSZJxuq~cgP2o$tiXNp_V zmHW4wDeq712f)Ro60Ofr>hV=0!;#ZZ`FHVJ@4e3a!0B==LAC_yGcD1!w(GVO zb$-LxM>s9`gd8@T>q=sTOD(GPL>i@h@Xq__z-f&+q8@zvZHgTe45jF(08O;Q>+ z?8q(?`&g$`)WZ<(yfV^7DxODZ%{l^ENwiK`ykrVLlM;!dxbF#ze6epsa?^6Y<``o-Op_Q2cU9T@B==A zh|EEZ(kJ~m#yeM-5`s7W2Vh5~jT`mx$EfeeE!>sveQ#IDcX!L(2yB}0KR^PPe*hB0 z^h-r>F?OG_V+AxVL4;Mp8A>oG7&aR6CE^VbofV9i1H+rhKR~Di9VEb<`j6YjPX%Mk zNV6RC`{S00kSB?rjlEdsnr$^x$_>ns`?a9<*8WZV@v=^K?h;&|dx%)@*DG)nZ39^+ z>zmEe4qsP*q(QWWvCc|kMZHS`@@b_AY;|J0oh+diU6z7h$B zH;^6V>@AF4gFx`P8?wc*aw&C!fn~2j0uys@JCZ1Ij$gGrZE&RnO)4Udkzqg7s}`3d zhc1NYpeU*B3|&fAu;0{V%}l$>0seX0!^Lpq&89P+4RH_lH9(8$#=kvlH%U++jhvI! z{jqdTu+);**?5S|7+kF#aBUHrZ7+!#6b{j8C)dQwxBMyK)w-b+>1XlRcg9y0xU(B;dyf z*uJk_;N=ZyH78DS&Ri@QkLX6*#;{4S?+5>^=6MGj0@jk>8?H$JSo=UoZZ zlcZN0t+Gwh^?Q(&r*l3pm0+u85-^UiSP=tjT(2&$E{&w=%KcSd7O_qbvg(e*wPdJu zsqBr87#P;+%-?4pg!oYhR@!Fqn{7`Eg+&I2Q#}+G$#dls5ET-9@Ij(UUG4l=4JI>H zrp-{inIm4jcQ_pF&uZkb8NKI<%*WfjR*P4wyf}6n&BDqS-|H-2KaO| zrG?@@Y3ImN=CG6bcCyyoy|>Cm^IfJ}WZg547g9c-RRYbJ4Fc${FWxbi&04SE9x(uo zo4XAV{N_1v_Tt;*>hj0%%4M}IVPQNd>XfUm$}LmI4RHH2hoR^W#cNRf^n=jD1G7vL zU{%H2ru^$Ck(?mKf~9X(=@<)Rp>qdkG;6L8S{y>&#y$lNR4%COam4!{%|VF8^;3#ixp}*wzz64%sQ=X5}0v&n$J75po--t0rR7 z7j>%7QeZD-CTQ8$0$dt%exGygxksMg9(%OMIc22aMg>WpFI7>;dzbUC4%uONRkQO5 zz1lY=WIXybvK6cTZ-1h=U)Yd`2(UGI29QG)5%R-c{5rTDtoJoMQ7SbQHs-1CWp}~4 zD)(P@6+@(!l-5z`zW0nyDhD2DqIGt2aVT>rNuK*0O#RZ3jPdkXiY^|Rb=1_bSuI4w zPft$2Ri{zm=BqIR87926SuMrVOBPiiagGKIBZ0{?2zm-ih)k_cB{fLNM;z{!X(?R( z`Ow>G+szeC)c|gQ1(hz;Gmbaw|IPKtZ>}|>9Lf2rbubfX2A`B&U8yyVn5cSVBQ3AX zy*gQ_wcFqy{!bjP#xo+F;%GlRP#Vw=n&avzR9XSM-Pl(pg^6TNZ-P8O$K|jKAX)jpK!=Jn!rbe5Cb|->7ZPJP4KG`!dsj!v! zj`I_VF=`273uxL;>9ajV@abAG-lSc#P|ZBfS<6B@5`$o=G5TB5MV}^z6YAgC7C})QyCTY z`(n@GLMexN&imriFaTW_G%?7?;_j*ihPn6TrPWQ`CkGk;e?LnJExjraJ;t(psB=1F zSvq1^VPoXWwlqMb-TBso!WxQc#PB^)c2Rx{l9gTII4RMa!8{9dF6cNIoc-N-FQcCz<{&UVp<)y|J;&$BgFdUTjKP=G+$5 zJY;`HT>}pP3he{zzWS(Y#boOOlvrciTuJ9}3>AjWIRoa23 zr^tEQa&;fi&c~8JP zWKXi_i~^}M_l$-W7F`FQP>7+l|8Qt8On z6O&svMUNO|X3*EqKbCRU*0uPJm-Sx3ve|CzrjM9AF~{U(PrCBucS!V3oG;bok&;ig z6L^TFxWipR96=C)MXTR51Z`h`uAOQ=@|%U;oRZaK{>f-A^FvAx-fo*V9#Gro%-Z{d zrQE#Xom}jg^oUO5S;R<&oJX2K1C&qm-!r-7&Xtc2sZj;v#w(hkT0u^St{P5m%q*W~ zK2F5v(bv0mwRD)8MYOgRO*t_IsgNS+$)@|SZ*l?r4~hZ@72=!_V*Z9=K!Q_VL2(f4 zD$Iv!B^S*2jF-u+Qs?E7B^@N5N)QuPm{Xo~KjS5KyLTcMZuylIfETyX7u)7Vb;|$R z?cB4I1|HSRa9Y=lUh6u;=B|#;r!eB zqj|ZNqGKghOt3&4RI09biEoSMD^c@FmU>UJGv+4{M3HZeUToU0YwM zVhme@p=c+_8OXp?iS=voc1<>d5qiVt-tFS_SH_ z!jS?=d!y5IcI&Bx8`DavjyW}pb6BL;3aAucXwl(Z+cfU*SPLrjAtB7Q+)mldwCMY+ z3<25hB8g5*kCVeK@V|`$g?+4wAh*QbB`LoTNm4tLH3j{Ap<}SZcl#M}TBHp_7PAZyr$mzPWx8RTapCExmo-@3umZn2n(tAh%qKi*aIT+}3H-D_%Ed zdGNm0E~Z1}k4?C@Tj!I+vaxteumQV2ueSOtz;4I~{*S@Oo%ux6?y+VmX~VJ1B9}nfMBa2?9gOwPA+JlVKj3GukEBbbcTGGaB{hE>p4; z=cJ2!xPf8?9);1Sp}CCpIr;R0w=pR4^`}tHx)SF>612m-S@Q)|zYN<*L-YT80b0am zm6#D;J$4tA9lrNNg6*qETKDBEyjcJ;e}g#&`!R6C;DDj_mSpkWRS$273auE}YfJ@T z%N@V7v#E#VmlEgdy_-!t6A~m&8Ss-@0$AVle3$ ztfj~rV+6MorS+W+N^VN?vq?J$1%n~%1}WcA*o2pz=Oj^pir2iFbXAAzo19Q#+fnRr zTd>`{QeG-)Y*OG#3u1y(Xv5eSC<9a~E3il0=f%}%sp|g$1i#?Xz=LQt>#jgy_r_nD z2;8!vL)^f3Z_W^jMwbio$1x4Gd9Bqy;ydTZTZZg}?OXn!J{7huv|vLWEl!WPmX+ELmFoyQ3(DqdKzuD2FW6JrJJ=rQ7?aKV0skg+i@Cp8>_mV^Wu<4X|YNl!$ zGj%9=vRN`Z92}TKhdd$22@k|9aH|2#ygvYo%(XKpc(a#VG{o(J|Ms#&ZV5vuP$NdP zqAkdawc=~Af)LkAZ@W4TO9gPcPOG*FGJ-sZJMiY(tPt65X;D!}tCCKV^48&X8>jWs zwCPee$|Aq?3N?ncy> zQGq9qF7fU_`__s4G#1ms-a>Ra0T!S*BuW8kCo01!#!vd8$CxeQIztI3BR$-v@-yEL z6=pYXJxCm!`YPQj;FB$U$hmD2B-xFwNNe@!+z+511)YqI0ID{y=tE4=y?9GF)~elr zbVb-#v#F$7`%k?#08sy>yOW8sk?PGaSkO^epih4Ds7$t7(+JO6Z&#U)twvZUXluFJ z3UlA8vxZffamUHYalk?^%jL9sO&P>=GHte0?<;>;8A;S z#Kuz*X9R}B%Y_MVRKh^V%?)!aLQO}kLAFs3A4GiOmC60PDXi)nC+OuNP5&g}hxX-v zYC1)}g)DVC(py;XLW95_^Kr**^0tPdsX6srgVU&~WJy};D`=&W zSO$?A%yNwjME{SM0nh3&|ARrm4X;lFO;kIPB|M$=hxP*nSRqcp_}D0 zZNu(WK!1ylcs%j{0M?}%(OpdHG_G0_wa|jz<4?D?xsFCiCbpVJlHq^7ASY^^oMCvt z^(K{!k?oEFZxlyz1%FPnC3om|qeqHOXGP&nTG}y;RSDHv=!ban38A}XfpQkzeKDAgy6tdh((hdMs z1&2RO{{TvJT)?I{BXwUiF4(h{X7}uP{?)YL3r$d=~bZK5c~EvA`N20z3B`HnDpem!$jA1&hA zlTIAWR78=38C><R%-5<>!0 zb8T00cMo%pIrJ2)iY?X!m?YN{11rlI0x&_z$jKuBAI7B-O(ZbcqmMkG^AD4dLVyn- zaC48y)k&6Eq>&Ohu3QkiBys>;a@ifnP&<%4>zP%9GMb9&5Xm*MP}esicw=pg0L*e6 z@?7(RIsh?{Po-!ilRdgXr2hR_y0%MWl6gJ9!krTfJX}T^KP1K@n8}xsw*1?;1D{M_ z40WU{G?@E5#yR%7g~%b5fi2G`rvMH)K7%?ZbWB<&jU}4cOj!$CW5|tIDUpC60=xzX z2RY+7%~qN@0*IoB%Qd-DQdRO}QhO-?2YQAztcZDF10mnjk$n`aJnanb@ zXi&6Gjj!^YgU3Aa?^L9e&mGB&X>TksRRxt>KY6p%WP$y8r}=jmGs6@t@WhN6oRt8d zPJKJ(w1a0nqsq|8EQw{@?<~szSmcudv-ojZ5TaT(CMHsC&ghkRB#usVkVhY`YAmh0 zg`P>S0)Us{n1v+suvbJ!t2HfGW06cU2zaM(i_B{$MIHA|Ogc0oW zn3PsmQ}Zz-0Hcf^GEPXPlG-$$Nt)=-J4D3T#6}99jgm4BK>&2?o|T%zvLs zu+c)6@Y|bvWYivF$vpDNv+N`8Ap5Kc`Hp$xgHUf+p$z+-qT0yPCP_U({Q2nJxo&5;0WMqmtT z!~4sRm}9Z^{3=kZa+0imU`^^*j+JV4j(I~`Lo&uAkNs?lTY=9w1Fbq`%=4Ke z{mSRcE5erUqv@a2R7*Pu;!HC|hV6o5Qq*MLidK{85>0HyLW>R_$NnIkfA;Q?aanCIzNB6!~LiCh^Rui3!C4fWu2o`dOCeJa zdk-+@B%JbkV1xev*Q^v3$xh5z}(2GQRKxIgEuJPU~8XSb2Wz#Oy86+p);$r;GV z$GvQ!W<=_8vU3_+-3x@bhC)#7xET!^lgj7csrm|FjV=~POsa8!P>g%?&1byRj3{!m zT}l3{%;8rYZ5?{&o_|Wz^PWh6^P;+Bhc_z|7G-Zn$RFo5qq&2r%rFI!B_)YyQ-qE} zrI$SNIq6EO*CWh?pfIRYz&Kv{?@hBFTuV0AiDZy6Da%N(;PH}so_=haRlJR4k_3)K zc@jsSUBQfpqUCTfat=;{WP8{~VG1UGCHX^f-yQQ)hAh_rBy%dn+nM9#MtYu4UurpDW2RD!k!j3} zCEWKn6G~pmMVVDqjyA|0y?dUgj%bqR!Zm?b86J7x63ON)k;f-iW1JGCf&d*dI|6Bz z%I#?JVOisggkhCv#!dk2bKFzZM>p9LGb0oH*=8FIT#1>5R&lu}f3|9|slJ1E0SR#r%2-o%IyCHN$oF2l-Gx@~D1Q%-R z7i{iP1ewPLa&iU_J^Izhu#ntsV6H&jwPy@B0h|why!|SOhINu(wLv6rfMF{b8;7^} z*0q{VDQPaGXr0uy{0!|JbJ!9(p1u3hl&;Mq8!g8@oL90$W05SCVlC#}-n&8g9TDc>KiH)pZykKOKVi^LEr)cfz$;Vo_yE5enb}a^V0zoTE zOdeXRxn*CQKPc$E`eK_KM{KOu62h-1@l4st&7m8UJv#B|F;~Zq* z?b_M*KTPvoXR=&*msZy;6uw*8TcI*Wy$0?u0qMv0PI^@+#j^=UL{~m-+p;W(I&Cq& z11(6>JUgv??>aUiuHy`L5;z5iu^WK?!dOjy1OeIgpPoKG@sW@~a4|ZRcze zn89B*X>iQNxgkz6IsG`O*`k(9h*iABJ4(xej(9o8IUh=p>Hbs_#~Yisl@s?v?=jD6 z%bjxLV|jY7#B*#w3-1vA$J9S1 zn27?*DRLFZQGjrLPJW)0lB94nF__tv9YYj-&9~Hp)6mN{l5NZG_IAkN@UcMRl$Gr{(*ns8Pv z(3%KUyv3cFeASG3xIGSf)Ov)IMK1ij{%fp~Tq_;S{O{a&&T=}_;&@EAjVo?zh@(b~ zWlFA22SZjlL*)YPzcGew#OJmTUrbc<#7a_KO3ofMVv&_X*pF+D$FJj3;zC<{$mB>` zR+kvT>^*w*H6zScKQ&~+oyyt6DxBl+sNuLPx-YXW-08Iso=T}F_=Y*-uN-FrquWI? zxlrL82grqE#Lifz=D;}Q@_XZ;rGS{?c_b-pCUd`NRV7CQKBR$;YBt6TmsoKaEJUERnR(7~Us1N#Z4d zVUT)p!*G6{)iole6Vr?6NJJ`=DYt1Qx|m?RrS`UWckB;g)6%7eIGgQq;ECQE-BS-kSn+`ER3MeY=XoQ}CZqw7~0mMIoET1jGa^KOWSJbqt=b3wF^ zGZ7UAPxfKuP9cdt$sPy#kQY22JqY8G{xv}wC(KtnWtqz^Wk3S9auqwDlmbt&^s7<3 zD-f~gYX*oE+&7MZgTV*T)Rx<1Wp)uWO5BZwKqvZ&=!~0VjDT$r$gH77@ z{{Ysei01Qr)<|+Ol!pwf$4vLfy)t8MZza@lPXzZ38S`KdnKx$`^v?uy=|m}SZ4aA^ zg_36d`@GHNqT@exx)6Gi?e(Hh-bOX2G9p<^l_(^ODv!~Wb^ic3^sA_oBdgy;-cxe> zh*sF#i~TnY`H0;e=Ssh_u%B$Sx(>!ETRzq)fvvWql%y|Sh;yZU8DOH58xze47rJSwu zTQ+C?;SD6K8mg}+B;XT{00$)C4oxhuTROnZvhJHLGcmyubm}^fWB&lxsZv6-v5_$1 zHrR4T;(5vE)9F&ozGFm9t;9lAWLX_?8#i;iB;;^$?^!g^?2PZU!zHj=H!{Vzub9z! zY@`wh=bobn+)_*>ED}R1#UlZTT&V{g$RPe+wQZr0h~i|EY-jhTATUmO=bnDGR%oQQ zlmRTVDz*fYAS~JXU}vGuJ65rl!ebc51QJ6GjEwCYPT2vNazH1p1~ZD(M2M!)%&~=4 zjbn%at=sVJO@_zie=((*E!cU)07l;DBZ1Fx$0C;6OL<_qMt`0Hc1DgBm}95o(v?Yj zqh9F@Ht8B~zqyYJB;4T&pa(eaPXie}`TA6_+e)eXxJZm1$QNpWdlES9f%#IzE-hfS zy`B~@ti<`aGAkZ3i-DZ3K{@P2UAw&Vyyf2`E6y3_mm)?a{Do#=~rmoENXx{nV z1d`w^V%jsbgU$}#oady)MFos_Ny#epK3gd4YC!1m>gtw zABoOA>LUp1V&su#W;XWlTtNgE1a6J2r=6pXn*}!=oSXx=dx4sfVklM!?H!s`Wt7IH zgl8Og>6~&urB_+^#}kxtA($!N0A7Qq9Mt!*!z=E4p}nou)gjK|ob~8>@%SFNs&2+o zav5oGZkkBrl^#`B4doS8WI#a~z#D-CW2rvosk_CMN#b=kXhpX5Dy+ls>N?}w>rtjr zUjbs12M^_jRpY7XNa@CFOv4C{8JPK*ZSb=O+6FSeA?S10Khm*LmG(KO30#G=srDUKIbw+`g2lOQEQ z{`NZ_IIH$d;$|%>EN}ylG4P>APaVB#B)hVYbTGBk$>onQNpH1dJ+_?u!yM<=Behn7 zD~~c&ibLc=n~|6R@(+Hak=mS+OxK-Cn=j1Js!f1hxZQxv!LxzWx7YNlQT?vgJGfiT zlJY4d{mg|Jd3&+A704j<9gb?m=E`#!4|#0hh7E0WQ!GXqTLb1&2?b9a_2Q#>Az2i} z?1j}Po_Ojz)jL?6OK>OiJh0L|x`sQX z5BHRJ1QYbeF-*HyV!>ygF=oofSfnbfry%DYLC-_SK?Q%9 z=lRqVyWG5%sHC8ea}uO89=%W3r6letImHbyHO!kl%Mji|{gPXhX(LH-!xR`S0U5^? zBsTXA7{HPhgLd|I4AK$F>&GXzVNHl6HjFmNvhI%tKvWhUpPgKS38wRLJ{IU4IFx{@ zJ7XB+40_eYyO_GSMr=|e%O2*MJ>+g^m<+e#4;{a+6)cyt#AARv29j~GFWqbd{{Ywh zX=H)`=+1UVs^4c>!*T2fP&3c@H2Z6b5-9E@hS?h=O&WgjSHH?w1J|JyQj zM|lc{o)H1r3*<7lr?)x$>Y=tb32q~CwrLx4kV`9`Pr1iDdvQ`Eg^Xws)vg&^_X-Oi zL5@1q3YSc>NUG*5d0T9ykKfKu*N;lVGP^33+b>>QeT>Hpl1=0f`1KOoh~{8Maz`X( zMsbsled(TBvqs4x#~sQQw0U1F(+;Sh4!GRMJuy|%No9t4BXaNNt_jK8&%fnX+T00m zCW%UULwJcYe6{RPP%?Py{VQm@GohhvTkPgVA~PY*RpJa8z48umfI0q@qtAE(pbD|4 z?>3FCAUWrrhqt9!biGI!=eE-&w~^Bm!>EaF6^P^aL!doL=b-hfvD`~>=EnjQAy>+2 z0Bo=yKkM5R)#^&NQ5 zIQR9gWlx!fmHfxN%_H19OoG{BTm+luQZvaNhhDWL@T~Fdh$)d=V{kYv_Y&^yjuSPE=jR%NEKyqZuvU&yTau8B;5O z#5eI|{d;z=#;=Q>7x3?eek^M@+Mb1VsrY%>rMr!$2&~Val}-r^FbE_O$m__j*`G2C z$lhEKyN{Ziww42~I^g8>=D#$5YU>SGMZDB?D{FfNwbksEZ%xIlbC7`G7|G9;*$eXw zHZ$1QHEJ=bg_kna{RhL0WgIqip!b%YkHZ~%M6=htf2+-7qD^ySV|yV~g>yTpKk5*W zR1=(%!vk)5179ZmPqgtA-X#zvt69fo6D{4dXMAz);B_E!*#7|a*Xnn|m?XB>d|9Z= z;j7(J8;MzvvqzParvBe6V4QvKde_H(Ht>$E7y-7KB*#51Q)*8Gc%cNtwXT@<@-N1+{i|)({z6iLlw81wiW*XOepFZq;7#dMma2a8T{|wS?QVebEGN~H7%f4KmE#B(=I9s>K?5Crz3Vv9C?y9D9uKpG<-M+5_<7*T@2zk3NOhZUv_19D+N@zYxU;rQ zY%RNuk{$sBoP(TTXSwh^`qbVigHLO@WrXD*b1N}L8NkP2bI^MG*U#P#ztk)&@2=|a}bhg?ZIrbV7e(`ourP3wma8<;dH#yp}z41nw%3!DN|<>$W}mGk~!y&Mh8q+ z4R|YGm7hUJ1y-F$DM>Y@v_6&adg~JSmr%K~)nbAzJnxFxTX<;HfsAq&p5BA$Uf1Bg zV_fkcjMq)I@(H;4Ww>jt%(4&RRRHxFCphWHe0*Wxn~xaY>Q^`RA|=xv*f#rl6z*J= zD!>v{f;000o)0~1>3@VaTE>B>Ykn%zL@RL}(#vxr$Ggs%lrJCtpaaspR_WdI zNv%&u6F5L9dG+%D%*e8V1cGCFkc^!2aN?}nZ*wedZ+ z=o&D>G4d>*GVzcUcg7Dt<6nzD9Qe873$15X38lq#1c=F~mHFg_i5oVi2>{@o*%-%g zO?@};W8$W*;r(LL*k2@8uRrf$HtM{&AmzDi1sKL~GEO_!r;z9PY^M<|Ta3R0@{Td# zOwT#NDMk_Yk?qv|PL#BVZLO@A7jnPuZLMSdi01+^ zj9_D~KbfvuMDZP#sBNdy%b1QU=Cr>%AJ7^S#);<%bg3@sRmP!$p$ zht!;USL*b!P{cwqj;Wu|Rq(ZN^_@D3(n3o(jI%+>d0EDMw{;VV2u|QWjQ-tfZ?iQ~KwDL=hvS28F{W<0}O}H*Qa_v8#43EuxP; zFEe75iBW;bKmB@4x^9NqrH$Tky_zs%Rqj6yDN0JkMJjAr=8hPoSzpRn<5wBOG@0Wc zU#&$5kIG{X>u}HpA%@_}J7b{qrIra67^ILZOK&FT4~7lSdCqvpV@!EKTOgoA9L_;9 zak+DnIsEZLgi%V&WETQd1ViLX8|0WN+}__parsp7EV0V%c$U)1G>nd7w-{9%sZq!W z7|RY$3GYcYqZo=>TtJaV2Ki=@SRo|i3J4`eGD!M*RF^omPqZlWNDN*O!*gVDjQ;?h zYh8q?#q=5Wbe&q>;esNTXJ{qcA+2tlu%K4cA3V`IVu6;nq`4wi__83_JUnRak!}z`ZeulGjmqTx3riIv{h8vcK zIb(ZyTjnuj5hghVoE(myT4GA~54&tEiE_xY5;KARJ#$y(WR+!E7iuVDFm=FH^(VDr zUBJ=K$qEZ)bGj|NnlPuPGINX?!NvA7j2+E6BxiRhu$(^7kVsf6{ypk6WDyeVB#EXz zN~++mJq|S14+>8zfK}aLHx=CFG3Zi1n z9Auuo52kU}pKmd_iB*CpIAuYey6??ut2c zx<>x!_v(4a1M`t(aTIYnsA*FX%)|nz*X!FfLej=%F0wD2jFKauJZ}5LxIX#lYMtG} zdCe-_Tg>Q(%#u8^@NhxKaKpZR4L@j@npWJ=ZzfPvqM1y)buWBh>>>w#>EZc;z=n7(220<67;J#)@#wZ^3+ShI>bWrFJDdF->QqMSAl zmU%cC8;3%D=}Ip9875drUFAsQ-yO_}gmi4~`umf`G6-&Fxw!!%R+Dn#MJI62Z$qEu zQO;%%#PLHjFhWU+aMDN*@UKm$Bfqz;KI6@01UN~ihiFf_LiIfU6r(nZN=fcXCAH17 zY@NKONST++Qdj}o8NkUP)tf|)2qJLnw4$&ZvfGYx^%Y5#Zy_UOra&1>d8L$NzJ1U0 zrIOFd7Lyg1F>pHhZL|&9?0+Bry(#=ga=nYcXL8eAnM1$J_EhYd>PhE3bRVr}n@ES+ z=PfUsV{PT;-b&{nDBJS$>HR9vH-t(cWMCI?^3>r*dJesaro&@A(GpY2&xs2E0IXN%^&h269EL!UMm9_4D@_p_ zW89?jJ2%V7_sFPj?WGfmU3~0FR7V?-SXH>Ch35#$vED=j4g!Wej(xtqp43jCGccNs zipFLUi`zzYX}5Vu>O_pEAcM~t9gnR=bf}Wf3|5moF_wm9+_Ns=11gXJV0a`q0~~cV zt#t*o&|6xIjhAq{wDH9X`FQEXfbw!UAC*#q-C}!=kw&{pPdOwg>yzICxn%hyXRBky z$%$g~R$>`cEKT>D1FzPW_E%XF3#)l8rJL+UGxj*_5~M`QO~oveEgTC|G< zSdHVJUz_(}24>vHk5UIeLG%>Mdvd#++eCcBl#@7-lyx4MKTP^og4@m`d6sE(?TWih zGGUk>myjQaJa%jQBRjiLr;!pK8pDE{&F{12sFX%^l% z1CQM!GZZWH20zQ5^`2#U(UF2lB#w8@#?c>KejUwe7*0jT4VLAEL1(nc{z|xMRRLz? z;xmEUl5^M+eQLBapS4R0w2~;1e9)OV9XUNVMxE9|kr(!1o#H^sM{x z%^VtfO)|(PR)pKYq{)t|Nyz7>JqgALttjoEo+W0DUUY3O+r&YX^OzzM2 zP_g-N0J}y8Nl*fwoSsfeqBpUVyhaC8<(rlw1#%2(cHr&n+m34DEyDzg3u)$AMns_k zsE@XB(EC$y4ZL@f-$?4l6%eFW!d2Vu#Erb;o_o}B$2G8HCD33aKQKFjx2 z<64UTLqQ#~q!Y@lhTag$BZQ7e`=oJ>_&KP%v3~SXpA24Yv!pP!sEb z;{&HXsV1AuRONM1~MC*InO;m59Decw!uO3 z1aVHRhBgIRMsvG8M;$TECR~Ow$vJgp89-F5Z@|d(JwMJXNVm*XuX8o-E+<%R$C4H~ z2KiNZBQ>_5`Ow7n$`6v;*EYr!Kx0A} z765d|vFlxQ>e&+YC!HhQi)_niTR6;Y+leEA)Q`vC@oaXINbNMi=JJCL&fB*yx2Hb7 zwOL$j+GYLi*fFUv?hVdP2|N+NLl|gpg?H4>2RRrVdlh&xSq$EVK`K+OX-8d%$zB%ZB!n7XpJ5+|=)$&S}Y3<1j zt&UeG8T2FT*z-}Pd7jtpfsL}|QM}U9FeLDJz{$_AtzeT((lug3Y_X%qC9$@KHMmuY zCV)v9IpZpLKSNe6qn0TL+I*?(l4(DEX%Isp$jA+hf(Nfp#+F-YEj;p&#+#&7*p9Mg zxxpAG^B%QYXd{W8lDPM89C$01*yc4lzMTmK` zM!sCQQMBVHAQPN=etqg2sG>JtDgX+uK*FdrlFcQ|vBNYbDArYAxB-t&e^2w8gj?Ni zc-;!ey}Zk(asswFP=16Gex9|W(IVmQ+1x`Mh+aSgG@$u=SSUpV<0Cv1)7PaSDF*3f zNoOy+YC|Yd8)JuT{o&MLbCM5gdo{Ff&mibd^@I)1xWFfz5sh68C8;cOJokZ?K;}Gw zECb~v9!K*PTHa*ebhA8*4EvADo?|qb+*j3ATUf%M1f=i>@AdC{Aao+#|lic^H z<4N2*C^5>Xe&dk4PDviUKb>h5b2@XA5)pALFcQd<$(D)}^KLoq{XhEDT$Eyo<{NbR zvgo0S_9Ko7<39Q8R)S3}wATVVVJOO!A-u*J_c-at80qg&$!hlZG9}b)Zza{b;tAs_ z!A=_^Be>)q{{TZzb4V#fo=9a#$CWXSB3;Y|7i#i&?^I@u?%vKsc4iSCjzaCvr#$=B zwqiqC#~krEja0OR4a$8FJ-g$*XC$v;vnz8fe=50Ajk)~~O1R2xJwe_`e2XMZBzCus z-O9!`-H9YPJdK#(5*zUP)|9sr#HSWh&LfSs$8Q!?0qS}VqpfD7j{EK)NTZaf@|T7T zM_vyeydKpCZ&~75vfpTtgajT4$3On6&P_>~s#8q48*jA{v#EcXjjH2tAN_w{{Du&jj}% z4l$no)N@4LU6&$O*>Na+vs^CdvUdQW_aBc#ik{vXXK>L)=E)_#VvTq$AnE8c=qij1 z#qL7~5*Sx-QS%)1{P9+GHJqf=Gj~$lrzCrszI5Dfn~a>VC#M+3PJjJ% zd1kn~k!&txd$DN=Se2BPSlHxk$4s1_J?kb&3=-|%Ea+rlE?N+bM{Iyd2L`Vpl31G1 z%^^r*I8x-WQcq5D26NJ-$&Z>uhSoco%r4IZ$B4=_1z!OA8m41(l0}AMk*(VvaI8S? zdV!EJRwGvPTIw0DQg{`LO9K$ac~%FvAd!RWX^~ANvYBCzdZI8yW&pDsjNoID*B?(> zsDx(jLnXX(gC)>eJfoCiLvCT*e~m@u+e-Vk{_nZL%C{tO*YT@YR)sF3irVZ-r3gtt z!l^v+F`R?P9A`ax(m-wPn%mBXLd_5F46G_xeOk?(<& z%)~0kg$0LybBumm0V9s2Q|7x_)(B#ZB&I-F zz{6*uA4AfrKJlC?%{@rhPFJ=Q3zKaam=`L;_l!FngVYRh&!t+O;gV1cR`HP>Z3Vr9 zvqv16$w9mpUIs z8R~J@2ivAiU$eKuc1Kop&hj4-A*a!$c@&~Rn?^jNv<~7x^ z(6X}KKxBBgck+0dVddYKdD>|`cfHYz;)Dn6E za5%~2_Z1|oBD9lzlH4IpvH4dF%7fH(JPh$l0lfwY!}+r`Yho~XmSfsCHNpRGxBtR+HaSpy?9j;f`D zdS|XZs;qA`^6X&Ig;nz-fboz&4xIDueQNd0LfIDH89c>SW+hNFsUrt0Ic3LV)1OmO zIYppWA8hun=gj42jA5UT@*=83dY62B%6E3yC?AU_5T3%Rk6IN zw`nl)%Y~bAZDjkAG8|M@ZGC@}*Qz z@-g#^Hs#Mn#&CO#@qvyj8Kut7dChYcoj{0f9%stIhVF7QYLpT&-E-wg@yP5qFyqYb z0ref~%gy#^aE#bT+`eRGSmbm0j8&NBR|KkuK51E00kn1GcITdI8bjvPX@twRX&y+> zLfaZ?T18dKKXeQMlaq>pt`$l1RYJ(j(>~McIjgY9ZT>`_Ni!2{zzV9TuRoZ@Lbm?^ zXjoa@k~CHr18{HifHC!|yF|9qDvO0l?h;rfXn1Rnf)dejokw+xR8LmI{v zm0~-K1Kj!^zlCopN4K^RZ*7#_f^3iWys|3On#KT21B1t(i*?EVS<-+RO*(&oz;A1Y4z& z7v8AFM4eTLJ-x+PvYO#!g`|n*jU9ID=Yyrl4jz`mid(`(gD|5a>Zt%=Ye*LA~0qimTbMzHd z&#{!GWW0ca0`rkw3ic&Ebw!Uh-V!Zjy0dHRn3i^vBn|MiH@ak)hn` zU6wU0(nvV^XB>0bds1?`2eBN2upJCtEgLE!U)o@zL)-Z!^`Gd!&&qAjdyS%K&7DC7c59yrfEYNJhezScPn zys)db9wpe(`T_^u@008GI61XNsI@!vBN0n&Bz{s)3=>A!xj~S}y8cI>X7{P>-ZZ!S z6B66YNT}q1#Be_l4u2C;6e~Q%CTzGnOk{wnMhG1aF_F)`D>cl1Y~=$pGa}N6phG6-Pxq2x41j<6&75IWf#e3FuFA(;2B<2bbnUB1G+g6D5^SPi*`3 z{{RYfWrPnD_Y*{5D$sqN)-sQts#yHrE&%lBj&oI_`!w<-&`;;bGcZTCC6uu0fOchU zss8}$Rx*-oijqi_MLNCAerhbJRcC>tWs!0ND-4VkBe?DetB*V)B#Be!SpI#(B%B|| z6egQUH99km-U^0Gel+=6thZuoZVfY2|`C41v_+sqfBe)XnBa9m$9& zX?H54Z2&h1+=1w7v@txh#*w~ZGC!C~5&OR0xHXea8zw7-@}-8@yIZ`64(tghzdeXQ z;Zwy7p?vu5X4=o?!*H<{StRZ|<$xoPLMhYRh~;gvJhtcoc#sI(9Gu~@K?H5V#~joU z$t)wyI(4<9$T>Lq zbDv&u+n@%yNVSvvm! zdk5PekF8H5{ifq=vlT$j&Se3aiRw#ZB#eHhwx-fBSA*Ecf&@1a+#7fqiUTNS&gSfM zj-sqIN9Uafm*!4OKPMuYBnu46EtB_QScf?{Z*27()9js1y})@kO@h&`H!kjT>D>PS zoK;ojHulVXi*4q}`dbw!Rbv+E9%jTYtgIc6$`jQ3RA@qnGBW~q7~|*WGwr%M@;t{}u|JY$p) zfChSGo=6_%qzyHYP?7nqaM_WzfFm7q&q0xnJ!)iUkz|wv%f_s-D(=AQ38iyYB+8Lb z6A5h0A&CRebw4uT9(^!L>+C6pC-TL#QcDvF1BX-vT?b>w8RQf1Qb%wR?q)}d8D>U6 zS}?`OUNSv>Dk9f%N{?$gpp8^U&nK2gcI2FLGlBj!akc!(pTsqyXylV@3j-J2QYIuQ z&UTFCA`Rm18D{=d~jLKw|NfqS)g(USE$c3~?c4t&U^1m4)zo+F&qG_d+ z0V6DozbMWWk4l#DZP>Cc(tV`H8r~&h3%6aM5D6oYdvJNhFh}IWE!BjwwbFyTqGF^rAsvH30- zf!ySOO0M!tBu^5y)?`*_i(vIR6*;!IXn{Z?5=P!u)FmT4aqGt(^|dNjen!bz7UbFz z-QN+kQiBfPm^7URNAUyP8jfhy14ky*GO^wiagLmRII7Z5D!~_*9vTMWm<^`~t~nl^ zYNgvwkjFYalgnptR(KZ$cJau3;fFZjkzGzUiOW$ZeGAQO=&{ZAca}KV2;>+lTe!(R zdVZBH?V~g(>#<&4-?>TEw*$~^1dwtMC)@E;46@3BB`m)w8#u}CI&|$(T_Ude_sa;k zGDaV8Xk?Ie0f*kl9X)F8~Gjl>{J9GQ-2ho2OYg2$l*9>?5!`qSjLPbDT;FReWA7$xHg7`AyJ@B*>P1F#@< z6@$?iD0`({#t|aCf=O6>y^9~iuNeHQX-+L>xr-#n7-#u&v~>Klj=r@rHYA(MvP*#k zWl@Z$%vS5QK_PHSC!g`G``FxL}>b1RgRl558%%;{%>lUYd@J zGBalCDIiG0J;W+XsQw_?0|ie99-LFIWriqMYs-nH0y8WnBt8D==OkvPlJYp*Nj@Z& zd@7`@S9W@kdyob|_UDRZ_X~3}z0|DJjlOHjcQFM0QL$Cb zpFT@4#(rQ&Oq0R(rrTa|8qANIw`ncT)?lmL6VY;c!Q}Shq)4OR=E}3p63jQp1fE+u zcL0!apHeCFIz-YLe4H7V$&NBYg+IbFc_Y`_hs|w`IuN|E`Jgb#+)$Q6!1wg$rCW)X zTb5_Hj!5DmhsX?S!12M)PCrVCT_c-oqi>UIBu&{*L-aLD@)lUySo0eKHp49I)R@}(Q@;tz+?cAyl zO#WD@??cF0e$YREBQaG#Ltu40U>?0ct#jH}+=mv0SV&~Kc{W^6k18nKvVe1*dhz{D zG3A<8zI&97q&{0kEO=HV5)T;pvIi%wanC%*6oTDiOPjc^r1DEVcB(@wdU62ojEa*4 zUcm`IWTjKd+JU!Z=V%0T&lvjFoTyF=ip{Y993C>cHE$5Khs_Tk%67*NN!{4? z<2_GqwF=wM@;$M3NabwWh1~Lc1CfKCovPm}D3D54;bCRU5*umYkD&(#+uFM5wvj5F zlH92!;hs+=moPdI<+937JA3=okjn}rs?flX2vEW-m10Iia!)wG;+k!IuPMToh{)T4 z=v)5)t(^W^f;5raXaC;wm^Yv!5p>|h$JE>L(qw}YGnFe80$VmYhRPMmzJoCx+rDbvh zTn()4BDJKSkSEu^IrYe?eDfp@k+ON{dw{H`o;d5qI@Jj0xS#D0Iy82X#@U^CG2=NT z`f-nJ*HtP>q|UxxRP-#wWO#txw%$N6Vu@9wP&yu-nEXvvD{mlk0h-mFNsj0sZ<`!( z#~JNU($L3e6k=(fJe{UVH#2S>$>;U%YRedeiu0c?2+GH@*4!U%gY`dBYf6b&#&ea% zN9SB6raNKvhx6c-NhvBYfK zQv|X0_p0QPO}h%2%CxN0Yz0Jcs8;4F-!VYdN+$T%QzRvD!S_Y%JG3oA&YEI6atqn>=$B4nMS zRw_3s{qhAF-I`&JRFEtD+Y0Rx06{0G9sOxdQt;q$Q=?H8cB+x>?0=&l0nB#{i>Yy_dp0^mfVIV-4<180_1>7jz)0ZahkO} z)0t7?f)KM@jK}6}`#fQB#uS~4Khux@#V2wpk!!{XoBQSCZewzv%{6kTa=%}va+gbl zW^AsLDA(L_zpKb)<~FwyL++B0Tax(x_WKX^*kgOYU$56W=Xq!rO4koj8Bw z`XOFoA95c_xe$EWQ7Bk+bgPy43jCT~sYI)i1jGEQkzjdsUvZ zk`ne6@f!1QlvRdE3!*AiOTNVlC5?!$-+1vf;5T6E)6QJ|!K1LzzV&{jW#a7z(7(L7 zehs;SvJy-d4ZZDWuE9ixcQ$Vs>VV}1SR3{Cq$kMH@mnFDg3K(`l7UXFvy_w(^8xpg z!Q8*%#^{h~p6_=)bd;ejrTW)9<{=ERYFoz@Nw#(vNJ{OByVoymCo{)FIc=iAE2*%7 zX0vXM!j09odt!8HNv2QgDpo_zW)4kXgiEWhq>0?vyx$=M5<4dX)gz9#Qb(DTyyfKM z$7G|P2iY0;Jzl$$?XU9AolRI#h1m;WMO*)uWwR+OieAz8vQ)tNI9J?N6~DE)`o z!`J@<@RA=dyyi%2Oqc7-8`?u^{Mp|buw$b@1>w(_VBX31(qBWU`)+}xa$l!%hqZsd z!a>jNRVe}rc6HA(->8JmAfE7q1{D6oO1OX=Vx;#JI?icj{kj6&=-$Q=53^Y`k>JRe?Jf zKQT{EsyX^uPUY$Hiq9ys&&;3^0ZN#!a*WwcMWjIR+^!@mvDYM8FzuC>O*hyCEC($i zS7ubeiE>~^b|}Mi#fmv){wwmCw9nz(D5TRf$kjblRN3mh&znJJXd4si)=R+72#X{} z4aqsMKlW3hUzr9)Oa}=0#=7a-8V%P9e=?^KLLU`XajO^FVW&bjpos1BJK(x0Q5_$X{Mq?nGIT?$s>8>@=Zv9?6KP z(!HK_&%%Z2U759;@OZQH&Rw+Hz*5O#~4R-OTEOHL6= zOhEi(r8?hCzn*Npe!F%QL*~TA8c(V21JvUah#U7t{3b^!p3VvmQV<2vsgY?6GnyV9 zt>MGNg$YuM@n&zJ++LKLg$JKmGueDH%{N~1LF8W6`JPbY=6YT^wCXSw4 zmJ%iAw2L;TXBrJ%)Fv5;1eJKL`#PM4+ze;4 zY=8mBqa!SjIxJ*)|C42qc^}_!d)>1ZW#i$Bg50<5K0=OM!y_q~mrr@SMdNu~~yVI1wrP>Z?r>XMh)_X@;p_EkP8X5{nALS0)i*PzR zvoHY~de^4-FWdbiS-8a`GJS`av&^TZ8KfD4G_Te2AS-b0`Fs;oQRQ@!6$|vh&4Ns( z{!h@~QaY1(9%h!>qu?1VU@PvfVIv2N%cJZPN19Jn%TDJ9OYyGP-y9kV*X5#7x{5NL z(pr+0Fd&S4d(Cn~yOSAeGr|Nf>#^F6+u8qiP)nnjk3hT#TodNb3W6aGJA&>v&o1EMMUqJ*?|^dNLZd@)Ccf?q&4@6&1SdSWFzvQS6XeUCeRrfo;_RclVbVKa4k> z#W6~MQ!LJLS!~~`6U;9|*P}G&A9&>syB{sPsh9dKyS9NiiVU|f8w)uLgea|E3#Shb z{f6Yg-n-gA|e>wgc`KI;oR;rc-)+#75khq*!uHR>ZHrl)=|dU}^-ucsBEvoRfH zW89cY;QAsJ(0dF2sWiM?YK2z0gDPvl#KXygm@ic(Qm3#L(RIs2v1XL$QGeuhgib=s z`=^D_(@NY;!^=mbO(cOZw3RE}8sHaeC4bm)RXjt^W>|$co!p+U8+<)8tve=)szp?- z{~}+hw=FR-{j3=r9K!JG8k$l1J%5B-XpP$$p>?gKOdYc-au>{pi1-`LdRRP8 zk=neo?RI2D5B3s+ur%kq5S#n7(CySHnP)K4w*9S8Q>}^lT@#7TJ#5{|ZB97*-jJmH zksDi4Ug+8!Vw*rBalMmS;hx$%x;Ki;Ut`bKruGpr`@_a<1@ewb@dqdeJGNGj8F4M* zwfDhi{{v`7bZ}nk!ftH65qUKe*AmIG@HcoDg^rmPE1Z0j;5jVE_58c{aJ9Lt!i;;T ze&`j%(2m&1#+}0|$j+bB>JYe)`y;JPR4eu1X-ivhR8(#-)l|#bJSp|Tvf)e%=2$fT zQc%=M$RdR~Puynnnwh@ezwYI&!fYzT?iuL?M0LXSZr`RYoG%;i0>NsT0vw&n`3u6M|y<(WcK3J_1qtf8ec*erQEo7OUjaPDpEz7HDEVK+&juZUg+~M+a;{D$tVHQTFCNYT7GqqsvSZ_`9>)=gANiV8V;# zdu)*|nBy&+1#OOt$HVsHgzGQX_KwH+=Bya276kBHa}fDzN^WYvN5c{6|x++`hOjI`iym_h;*`h!qfF z0ea`z;}b5%XC)saGx;NH)Bzd7l(WM z>2J!7q?38+Ao{|x^r})wwYYS0ew%nlXKSLlzdq)sX5sYx8nkpmBW?V`RxBF2yqQ1q zJ~g1|Jvew|=vy}+N%P@`88_Mi-j9OhG%my(h@9PTP0!9_fiW~dw9v~=qbbyE+1md{3Bk~kL0kEArQ_iy6)sPe-8#HJ2Z*$VF=XKC(?`&X z9bFlK!O3xxJ2rB)Z}mFqbqTy~H+a)ej|wkXkE^|e6&!C?K{S|jCU=id*IF#vvu{+q zWW+jT5uV+xcW#cLHj^;4=uJsVkZPIU1S(&W1d|*x=tso!fLAhmi4RP*{#sVM;S8sY z)ZW+xs?Cl_4!5sqy#L6Ob?(fk3+dXp9uybAYb;OqcwUPKwvCOnjLk}u>2IojKbOy! z-oz9)HyyJ)G9H|?L#YsWQZwv0i8G9Zw6Vg)>yZx?kXmOi8{j9j)Ut{uAI40gzo*pC z$L4b5I;|RAPYdU2A1Z%g!1ZSmcs9yJ+Bm-bo#CF3!XZd%4*I`8D`qLL~wCa zAHHN?5BC&&%x~ZtSJ+}VD>m|COppD!bnr&zKV2A^=et1!UjRhb<=sXT*7~q4G>rmr zN_-GBwwsws?o6Dw%Xjno*Hs%!=p9KYSoTE!3V#3v9giJJ@on$XPi5{6`z|sN=Jb*uII}|qyXwIt&50~n!pHDULu(l3W5g~0D}4w>oq z?maC>HeLB(labu@&6j((fYs5X#i~?d2{|%XFy0`S+$6PsH7;P?RiNWv6SWdzS~AfC z*GLIwyj$@Vvqu+_IgZ-3f7tONdHu;z`GVzIFjRwK_Vz1nPA0B%B)=$)!HwpqzPbwV ze3kM;7tR8^``rVH`K};lH!CC_@L~fCrJYW%Q_A(_BPlWWw(WX-COLP(WA6Lxy*<>c zXGp8kH1=rDF2yXE7jb$W3VrlVP#PTrrqbiuScubNv)^iU zrT1^mvESU^%obm{6ZkY_`lKwf8COyWENxHn3nz@ahAwMwA78daECCySSI072|F9R) z7jd=LP%mJno_|Lqz0>Cggsb}l@)vZzqJbqN03%v#^dKvj$G2TkrR)-1aT=p_&P|3q z79{x~7)zCKlyX+@>yoowa#mML=9AMpbs}jB*QXq$bAFh+dVrLY;LDzsnklrYFdsX+ zd~J0<@eZuPq3C>uAuzNtqapL30qEen;_=&+tTXnZz^J+Mwt124m{1LL&l-b9``cYZ zc$2PDmGKA9VVZHX5VE=1f`v9ar3U}*XR}@tQt`AP;wZi6o_T)cvx~*6VP6<2Q9t&Z zjHAzP1u=UW}_EFq& zlz!&(jSSQAdM2!Gd`t(erkQDcrCrmt;KUP|*5dn54fEuVaq*KhlzS z%y9aza1~buHaZOiaW3r_$ELIQ28}#4&pfyoBzv}G3bjGO_e98)crD&NBPH#&F^|z` zwERCYjr54uryMBNS69@TK@IAuZD(WNN~cGZ?*9S0HhLF(&}Kgj=+^%SFgM=~w_|^T z;@otYd^-RrScLbiS8;i`P|v}rwWIAZ10@VQa<{H_>pdf-9EgWfrnG{OXnTP_gM9js zhbB@ffE-)G=BrMBo@D{~ao7*E&vgRR6IS7FDc)9+TrYA5!vZ61&DMfu*y(OP@d7CB%0 zO`dtMU!j*BR}S@CAeJ){1y9y*R~U{LG)sZ}gfg^+Urkf36aNE*?K0qI)3vSHHgVi` zcazIJ*y2?s9%-b%lY7eBiEcKmu&ZR7r|iG-o02Hc-#fFI7s;rZLSeb+(I}$daivzy za^3!Y-8-{6K)a|`Aj2MR8njmM`331;UHBLU!P%QM$_d_s=Dfs^nV0B(*DaD&O^e`7XM20*jmYFNQ zNTxF<%-Q&wqySA>r>Ptpn_`C-DYC}FbT34*LvO15WyU{MEUNV@UH9fs&C}+5?HJBS z2wgNy+ZgPFK|&vd6Ibr>xpCM_Jm$D{u_KwD1!6l($j1-8_)W0OfyA|v_#7H@oyiQb z2Gr)--hI@y8vU~1Tu+;8^mcimD|6(#jMXn2g{_UBy)+M(uq(-DB;Fu>6NG-k^*Du- z);2V@KW*Lwx}$)L4#CFslv$zrpom9r_jDZty*-h|9PAmfTKibF;KGj&?F)3QgjEIo z&+aC#2@x8o@5M;B^oZWMg2MzH#O-QZhvI;6%cnSo{9?z)&>s=Bjl^4lN&f@55ImHk2Nm1dvaX3$YD6nOI2(gHzN@9wqYRn9=QgZ_*9 z%l19G%B^H35vVs&Q1+^~<8adT(b=1LFvPiwS@qWzP^=XNva&=j9g5{Bx1~Pq7Ph)u zjb)(+Fr?xKo*kl?(?uPNge9_{&0a$z41Q%67R`LI*AEft_mzaZXx$0=C=S74JBEm2 z{Fkqx{|xj3e37leZLc1+sY*_%&c}~V#MhqcP&+T4-l_|L)v0AdMwARWfLQe>3!@+J zjZ^tJ?ge>i{k7=Yn|3aks^lRto;?JE*i51LA=oS5OhH#VN!jgcf^|S(pSA$rC`AyLkdk{7|~p(l$k+ zC)_+sSUeVU)L~OlaB)NX=DD^e6xaPBYEu%hNM2Q2`w}lAf!>48XD|E@;P)Ku>L(Fk zk75bm%0Q^!jtQ^in)5G7LVCP#RXM?H)Qp;q6qaP@>(nz=a8JsGv)Gm8(n?`(@po~U zryc4t`>`tu?8}utBXAbPhfHAeK*2wJ+*v$4_f6GvT5DhRpq>?bl}V}hipvj;%(`_~ zMsT`ZYF;Af{ZI4W+Y2p0ly$f~gYsh$Z~Gr!InX`O z9`-A{wVc@-*q}j782n2LwYj7*UTj7dsu=wW;A!~@CXHZXxIMe=crx&1tnt;)OP@U} zx*WPMDWM3|`lE0<|IK0vwsR2Z=nr*at~Q*!C>Jkj6&r`<_+8;@=mk#{nfYKt#TpXo zL~Xm$&CGIyWM=nap`RM-e$c!XYivnfabfvISurvRmdMznW<`+X3RB6NZ^|9EucjW# zHJ6nw@T{+47pWyvHoAFhsdk>N6bZ@tyz5B5x+S>NanG@GsMqI66GneS!Y!c>)Ukbh zhY zvOmipuKS|_3@(WfC+_8fV;F6VH_%JpC@+YjWQa@qWG(V*nw#ct0XGaFkZ@RCKYZzc z3Y*fWGXt~AF2FI142!*j1p;P(Ow9T{u-!)XqO2Y8RO}Upzx#4LjQpS|;alFXv0);X;h>*7FVSkp@boRqv672a%qDrzoRvzLPh&>^K$k#LX#qs zmmtsA^JNa|he$vu7&vGE3X1#!x2}A=>5$?k+sOP3pt2A`{&=!uow)4V{_y7*1OUa! zB3(um6yze@+&sVXn%dh1W?Rgj>RX1#+17>peN+m4XVZR`MH!KH(;C$L&ku38iZciW z#}eR|V(;ZE5S>;8u^`Bb|K1hM(PX`W=}F*Em0yUdf5lJqU6{^ZYK&Q-@_`?tfk5+( ztAjLTi#r66bt+RPS$2JVn4dY`(a^D~|C2rs{7PSJO!w)4!Mb!=UZo{gF(Xm}zW)Cf z)O(@DqnPuylANvb{oo1A6J?F}yWOE76cpWSjrI`D8+`AOl(->h%n>GDe(9ZjgUpP( zDkAA?V-wEj`OT`TYBBSIqn_>bd%N~IcJJe4qbgT21wsrbx$n34EDka_lQ-_>`H$Kl zpry!cz4+^4FAxox>3LflKtblMcX#UK=^5<}Y%i@uRirZR6z1)i3ed} zcqpID%p@6d`P4A#Nv%IvcjJ1ZVA?#{FX6 zIyF93WJqI{q&nvKdqk0Gi_d|q%8QqI&&)&(y91`^*SR6f&K*FWZRyA~@ z>0MDr!^S2Zt5Yd$3b;znf5C0t>ELcJXmwR*a=uiO_GSBK;1c%EFEF5Pajl-~1;S9) z53eZYFx<739G=#RTu1OlMpaM)yB8A0Q$PzPUzPR`c~X1?BZWcE0{@>Zrs(kH2&=KC zLFUtg8p9tk!(S51tuc?JKYl`y1qx2z=Fqnr7QJimr=U#4nlxPnV%_qe9RCFvgQ6o)U5WJBc-dK46} zh7a4x_kG^no&-G|%*m;PR18VKW6&;q6&>lB`m{)7+yh4tO=sQ~>~+^vSu47W&ub!xvCuFc32h zHsZh}$D3=3XBfwE>zipYT>?R0Tqw2c3i6Wr4JmUJT1nU zs*324q({r21&^78g3P5k)IMbnuU|zmnPU}#iKd@2#E40@QmbQSTrd|64{yy&;JM&xOTOr(QP^#~MD)$k<4%ZVg;l4rqQ7Nk2X!W?CW}30bN^fO7JKQ@l z(QnqJ=zLTfseITWz-N6@{nm>}PT{siaG#RDcs3#174jI?vp?Y26_U3S7ayIMwv)pg z_D^%DbZm4M#q9Hj3wwWEaPY&otrnF-VB)}Av;ZO_yh#sgwFLxjfjqx7ci7Cdz7vhJ z8PW7Q#5knbsHaPE1u?3}kr>)fHZ?^Rx`HSyC_VquBJJ+!WbDbM_- zm=71Jjb||}Ug~=0G>CkJf5GORZnsF!B6}OZrJ|ZB3j1GQ|4Cw2Yk&>%VOUB&+T$stn@Yq8_Fe_Z z?Z|?)gfV^IC9=?=3$9OZ%JIW>$#+^Ljn26AgYrH}Jwt`vn~s?+ZycMR48a5ncw5FX zLZXD=T`*QTM^i<6Lou+OPR7e>9Fdg4Fp{VYE~dUR-U8OjZ5F^$`R3ZEUn zEy>O>qB~q52g0BKoOmrQ6d1+Yi6U#jb_Yy?2Am!2j17g!*~(1}E>Gvdb;ho6PmS-* zUHk_qik|1-!7+O$ie+(o+*W?=cAD41h+L9b7V`U^m2SHWL!ImF&X>0ui_Js+d%~?l z*{RYBa)&d=m()No$gOD0Ub5j~vx=|3%*cSCuNPOF;=xzy7DIbdQ+CU>u$0q&B0^WX z|ICd(8(k?5jt{S@di&9z;J<-LAHj6-Q(nUT9o<3-ibfCg7c!HWy8BmdxxPJ%--2!( zD*J#T4fP6_$J*zIL`jZs?!@CA z9i*k~B0gV&l)-$+0lt(f6Y_&eYWX=Mqu?Ka!th@^K-N`n|HW6ENcXZ_MN^2(;Vv80rmfP4rats$7R zy|O~T#3-&guc4ty+Mw!$jV)edOzExmioNn&*GG-8 zwS*m0|0dJAn=c;uHg}s#?vd+4D7BXDamHFsj2ecuWyF0vY)Xs+gz9FlyjL_mjbPU*0RT0KYr=x z__`wCp&*Kd&WGjt*t&i)j`3v2cg5o#NJk6N(Zd7EX2;W zwAIOchHX;B>?HXjZE{`Zg``orN@h>P&EHj32XO*1ej&JT(+pED;dfig`oR&nkdCO= zmKjv6?__YW1o8oAn4z=FJjIli;kX)hFV(fwXlEp_RhK`uWxhIm>p^LV1iUVn&p9s$ zZD6Ws(QLxzDPWu3dKC+e&v60(iT5TvUP2g1)-PGR|J6=I(3)&J7J63(g2hEcaZICm zA~qGb$(r`|`Q@qj2Z$&1Da=(hj$r24g^)9W7T(48l`lz8n+Qp&M4{m~E3v=9g6F&` zn4JCkQZy6zVzszHO7+jv!fZbX_>pwXLm6Xq;1FG5$jrfo4=0DfsDJl^dnm5%p@~tO z;kKK*?yw)G$St_*#NX7`@l}JH8I3AHj2$g4_Slc<8Clpk5R9%BX zo^%J4T9vuN4TT?^cUH07`rZfE4@_?OCua^rDxWG%mU-Xr%SD0YGIy2X72Y_s3%q8jI9@FwkY3J7@G{TJi!>TO zFnGM+E~`-TO-#eUEEqZH8SY_n)X#UC{7U68WY^qL!6cm7OzOkt^$_8ApBcU$_x^tz zCMZz+;uYjDFRDveu#yOR0=KkGz^e(Dh~sVXvhc33y*<&6urE^LOgMYf;6sjh6m;3+ zS;74CjA6Yxsc`EZpyX?gk1|7B;Oi%)9S&YKd;Y4(u`Pcrij$~Vc}xU@3t9Qo4ETp~ zoWnsJcG4M$2D@R~K_G(GUoccmEa6Ak73I zOSqj?5Eu6~MpQiy$h%+?)~G8}m6gm&@Swxa4e$QFJ>HZ%lE3Nuva#O+dqk)7@oCMes+@XW1-rCjPO{^#DIst@ohLph zY^_dNqgm7E7Wc#|BFw>Q!NxCv+TBw48h|!=a)c1O=av5j`Z~w0P$Z)203PjTX6~5J+tr|b zXk1#)jqm=4lN_yoEp_DH$6vYzro{(iwiq6$1DSW|DbAcXm2l68&+txeZccc$*sy=5 ztjh4fpjm{TV@sc6NlaiXd%d)V( zyjAe|M3ut;*hN#C&!m#)%vMb^u@XeHO^z|KyMJfU*2O4g55(sYJ*y>%x|flX-pvSD zUtYhEXp<1>7iF{;(ZZc^NDQ~Z1TWNrsfNg^-^kUhtW8@59rH|GMzOyKTz_?hGNwZS#ch(NYQy(EmiE^(gbD6BT=OJK8qIj89|Zb4GarI* z&$e~Zl+?#u9d3Sxd1{~V$g4U;=y7I{6?M%2(MK2aC@^1q1L?n(HbIYY35AKpzP_Rs zLLDN_1;QLgvpa$)M1RmBa-znY=ON)!HtDBY5%t(=E%)IFu5GcT{@5-%+cJQ(Js#Z5 z5iL0$U-($raoct85WuM(7d=czObSNyVlWFic?{OK z3O+=kh(pqV+#(%qZARC9y}c<7zFNq|K#;pm~PV3I>FCU}%^;SKTTiEWs7kQ!`wnI$9WrxIEZ>;3t}HEy4L zO9rzTZupmxIn!v%aEyA*dq{f?w!Nn*ko_RAS)wbiCQ0JTGi#@Ydci%|4`5i&_YiB| z8Fu{8QGXov8?}R(TCK_m{gjEpO@xd~7~}6tXBhGE*hnZ2@Z7A%R@E-VVJ@O~8eit3 zVc|H#arM#yBOqTOt-(h9)zpN71kwYB04k=qQWxpgGq=%3Xt9l(=Fw14`}H)hYSM(i zOS~`KT-Gf`i9SL)2kUu#QtG3LQ*r)A43dkbxc@Q+VMRbv(CqyNAk)kyRn`59M| z6bgdyq9`$M+JH|PD%Apczlle+MsBurp{BnN5JOS#4=eqS3f^qpHvhN7-rK#C2oAD& zHuU<9MO6qUAs)ulOQp1ZVR|Lf-gwiI7%(g%SFPlW>tZF}hz%xAb*(mkrKZnZ`hz-0 z8+B#*DlCxUk+W<8N>*%!+9Gp5@zA;kL$TL*Cu=+@K${p^KN%Rn^1ndSFp4 zhCE%ac@zqNXz#!X9_P!GlwcLACsW)^O=_w)DSEvKk8Sr>X%uICYP|>5E=~Kc5Lks zq+l7Z7Gj}fGSMgTwE4|d-FikSHM1IenOzg}Wmv|l#62TN;p_#EQ!K6^g9(gbLBW{| zEETjhb9S@Yf$^W>;+$BaTXi9*VI!x4niRpV!vH!Xh!i|^ZXqtqbpd0^?qHm&uxJQi zH#tui)#}Xz9WO`CQORqZA~;zt*8C^S_0|>(nWW1HRD)6E{C#yrvYZ=MTjWiuaBUmB zavkgQCZ>YlAkYHQLJ*MP{>S{L->)=2gf#T~`<<2`hf;i8B9Kkz zyqb17(GYKrk!QND_!tVL@-HEx{22@Xc zfyQ`xcG=(zPPd4o`4TT<8zyPDp_*QUyf>+Ju!~@;9F+Cue|X!`pE}5Y)$&kc2=QZG zlvN76>-OTp1FbqA2cM0CF3$$QI}Os6hON!a>qZ10HmMYTHVgev^@N)Z_X?kuIdo+8 zOkMRjOkP#Q)5d6S9lh;S-^I`6h~g3AIsu@|?uf{lDJ2eIcMerW%|a_^@r-CXleTwG zicN=_U!4HMBl#CHnkV#<7_)=98mlS+PAgjLuCTwE`To5}^2$vn5~ewSu9ZF>H-(V{ zBV0#7H-wV!OlGIN+$4!rvy$ViaKD=mN}E3EBpp5r+s9$jI}tEW{Ynv`ksIR{Ng%(Ae41$9iYsq-@<57MQg6RVk%sT` zyG7$QLwiTz97^R1WxB@YNLTPCooDOM+c|9(6C*zkpS{Rn;@zAx$Ag(K-Oyt^VSVBd zdd#npOA>>!wHWtQVBnJM<`PleK_lrY*)V=;%_*);Va@k_RY#u+`)$JoI71ca&+fWsKdrFG730HQvCjORHNkx?V79@k zTY!w$p5>@Lw5bmy$7`~JLv5II!@@D$zT2);zjXk%8vs`yFLE{fWqxeeMFMi zlkCdRRnC*~LfwlFZ<)X8W@w+T)xusoIJd%zuUtKoky)X6)g>9L1t?(k8GX3))8)aE z)QcSJwr@FBfDBV8QR8E+Vg0)qwvZszn1hb%SZxhWNmIY|0Ldp(3|;wlvUgbY?^2GREr3pGjLTW}EvP{I7WQea5DG&7 zP|_<$L>+>^J0iNk{gaXCD9|7ArJ0rg(?EcjzUvYFW5H_Av_-T=<=Z4a-{kc$y(z>9 zgxZEe`j<{Saru}Gok34bzZ}BKUFwkdj1LX_hjXndRxj(V$zwC1ORoF8s#!`64$boJ zAwnW;EIblC>jL4IEkVyaZ{>-K>ZRR9VoaA|VCWAdlndp=lnGH-U{0h6s3I3HlbTcW zjVxr}q5P#vQ>PY=F*P2JyToP9afw`2iQ81cr8KxCJT2gj=~~}LJrmE#W%;X6zJXg` zw-Uc>Uum}PNz9N~XI8BXtR&haU+u|Ut;a4~k9@8=v>Y4qz&3x0(yG&9KAKCB&c^5z~GmV+_!|%n< z(}LHcuJLC*WoKd)F$1wtz?IcOjk+LwW8fi}0+B64v&iY+%N_$WzWtu;(Ul-a(fd`p zVmmg@GZ;ddUaDcz1@FFE%k{l#oK{GjrOv_D?<|boy2kUE+uP1UF^b~j!FcuKwN{_3 zrF-K>Iukk1HW}k2(+X1~mLHL7?n5XZR>CzSj6*_+o=-A3p?X61U-B~u5Oyw=dD_Ej zb)O%JBvPE*f%B2~WL(2#?~Fe`#UrZO-zl~inRYLy_gg((ct4qn;uXVg3)gmXUV}%nTUW90Ff`E=IS^fnEGj zrL`^J{tU(JA-^GY?24Ot%>So4wH&%9;HEIf2D_hVDL~X<+$R6AoGsfHJ#t^E zO<@EwH3CfAXz#_N6vDq#Urw3nWkz%lJ9E%(n1+74;q0M3=*f4VQJavD8M*8_A1pls zb13zT$Qwk!p=SSQ^>Xa|{&;rbrEleRGya*hMw6a@TXa!91zR&Ah1upWf9e~-{2UKu zY1NrjhVG(Eu45M>Kab#CJdQRMN~GOO@}b=%uGB*&o--qw-tGNV>|$|_SgWvQ_-)tr z=wSeSjZ$YAYjAUhPImObkQOc>mfOyvQn{6(IQ!)V>YGKS;TIduQ4tY4ZbX{v6WIZW zbnX4S(!qYX^)zclr^on}M&d<;mG3~>9{hXRE9BEfA?+hEjqv3JO5sTW?180?c*!t0 za#`M;tX!385Ru=Yv=4aV<-Snp`4^7w=PEV-)b$oZ8#hD}I8iLoZV><2S4|Wxy;0GkZ8!^%B2j06m(u@?X`! z#vEaGDAm@P$_5G-k=DT#6f#t5sGo0E4k)dz_y5RH&9X%T^JsRa%Cwt9%0`JbA{Eb& z?(L-Oze5D?mH>O!KB%v+Pp`7QCt*>mZAU!*p5)<*Isk_Sm7vuaZld=5YN6RnnXa!V z#M`yfr#BUgn{Q;fKmfb+chKmNr0)QM;*QM%yE#L)oQ-?F(l#0753Wp@>cLn}N}+r& zjG9zx|Jle)6hLg={}J*%7DDIV*9dOXTg7h{~lTM!sMzzqF>-J!GamWjG^L0 zG9_G!GgGjD^BSw5B1@3spgvMKT)#6##eg&5T_)g7@>x5ad3g(4y82Q&?`h+Jpj#}6 z{_KTua3*dhxQBBwr%j4CIo|?*HJ6+$j@3dllJCmN8N{f2v{hIHATp|@epumn7jF&q z4e(|FKX~{RhVSOLvH8C6f5Evn7W~qU4hG-VNEa-K_O2MQ!E-Kre}++52Vpf>^wpH+ zgwnmdeg`N>Coq@1i)P$Tuc-AFCk<^?@1ru6c9?zHE>(cEd~v7BoY>Y>x0mB*hG#nB zb8~0}Pb@2ln*5%5!POtD>z8`imBcrby_gV>Km=P0=d1!Y*_2GFDPPEQ=?bCe0W3&j z1!qn1=*4GY=ofVo-kUL7Pe$VFJDHo&O_h0^wJM2G+L@r2Bkr{$DT2m$=B-P`o% z=wdhGmTxjtJP2ERZy=%XG=PjM3qam&rP6ZfTA7Z19r!40^<~1=_0Iw`=r^Os1u1hg^|eXdombiQYX+;oBGLcA!aJjF zcxBYxfQQ`+zZrH+35)L%-VycOuem$9j+-LX*WPIm-@EQrH1scT2sa0RD?V!?%WSmr zx#h}swf?AicUzk-mG+6?W3Hf0(YnKL zj9d$m%fE?Srq`)OM;k}9h+IImQWC<#EGjduFrj{X;6aA=&1aI(0@}?+sJr<$`XZ4Q z=*+G#3}RP2_I~E-@^G^UJ4EUq9L=ybpCfX(yMdR`$&2yM6hX(LLx_S!TiSLd9R{f| z#>ewKg4XT~ptznpA79zJ%GAxb$$Z#v*$rEBn*8f*hvo^TDhJQ+So&4TTD+h%M3**Nbh$A9!t;^&_3@jHQ5H z`6i<*?FjoBURcl8IaWPnXC?;v*2?wKV;%Ec3zbfSwY*fkHV)mhN98a6{bBv2wKbfM zUCo&CKtETV)p+gpqje0n;PIG#NaHTsCOdH6f4aFgkq4&HgiGHrMLzf|jsvmL;&tU6 zsh}v09V^k40;im3Wd4r0`MZ$hQXe+NDn^}}4YV_y?-wLM*z|ti zRn^`5M!1ctw?R7@rMGvcY6-RO8AifCQ=x+cH#&?SQQMztd<$!`TwQI;=o}R09Xjis zGG4ko(G}S46VMjSV1%>!@zy|6E%1SbYq9_j{~B9t1r^#+(^NI|wxJ71xGO0Lp(Tgl zrrW5<(^ohbF@)DVigT9^(5~U*{YmDUp-LyWyVKiItg*$j4b=et53z;ig|grmyDTdi zL;<&RadzP+Jllh&3ei>GoG8KJJ<P@3n)M^@m&T>1MQ)_lq8gV#<5<^RlD3SyCm z-&|^HH4bSxs}<~Mj>fV@LSq+cdVArIcJn8b6t71w~{(zjwxG!<$83bX(s zZ8>#0Gf|Hr!`1W?4RxA@(I4$m0iV~}xf?0sHg+PqLEOs?48B# z{9+$`=Tj=fFhdAdF4S_>?I?rPp2?eAu%i8-<8SDg!q(3v$9OHfJ^361nDa^P(om&k zo34hi0_s1Uv<2XfYn!hM^xvS`m$b&E{sTjiNd6+}dx&)=)hqlF>uD8qPg_h17ul~r zZ6rZVl-5M0xorj#1Sg{D|R)X}t`X!z;S}T}7ReQ$PAEvZg;l zcr7q!cD%LI#V1Dn;8jlb;~?PPl@>CEr^<6bB>qXf85Q&xVY7WZ{m!lVuzLd$yB`iX z+peHw)|z#%S1s=j@qh|qwRd+P-uAk~le+eQ02x8%zQ+3EYFd5W)rGw6iLBu!K`8@* z!zUR7>B+B?%&=b04*gmEfr8Cw=Ih%=*5q3s1$diEz0!_7j3`H z4tU7VBOH^TdijO!*4EQl(+qC}65q74F2?g2^Nf&kco-hl`d<1IYu^&J{T|xgbgK}I zR_b_|#Tu3%jNp(*Ugzu0e0SsThcDqj7i$My)oo^zP?ks1{QJ*3W{sPSpaiJSP7Vez zdK&Yp;bTf%yr%Tt9oAIj{p(!u?+D!A#J6(+s>5jgrE<2fg#d|+qsIkwaz(`@Irwa|G>`*;#Y3giOV{q0T`CPdrz+d_MSx;)_PS zy12HAeGcaT0QUiut16zkz&o+mpKn_E+Q!*zv|DLyS?>JV7b|gZx<+qx_4fY&8uT4E z#VKK-y|Tmhi0N?fJO9Xc1BaMoYx?)cQ zu5dZd2iCkJ;ZMb%4fsF88sCStO#~(__xCP z&Vw^wSu$#o-cL1+wXMrUyH4dsW&R*nJRUR8VO^AI(5X*&-HFbsH1~5lvZk>U}G>GqPL98|_wQEyv1n z>&;o7TtyDZ#9_j#$}o14dV6%Nt1GK}i6pvNVqqID$S~Wu9G%?=>Bq6F(vob1a7P?g z@;Ed3^KEA9$j5(5{Q@%$noAaf#TdYkq;g)F~L}=0N9#|hP2e|LwtwC{NJQBdrh-WQ0`$lI4T0d^TFz4%C z)TbFU%#}3Q-?Yxs$9XEWP)JBYxZ*|~aqa=Aqqtd?Rgy2>0f^a&<0tg<*tK%8tbQ8r3+y zhAwtQ65PsWGP*RZ8;(x{7~~EQt(jhx}_glH}-1u9C3mui^3pWfaRP#hv2@_&m0p=rcN8&OMwPu)F;z;8_ zmdQId*PC~ig?js(dUgD3C06fZ;a8oTFz!(*tE7vxVl)MIt8>ZEQJTtfAS;Wx?F0(T zJ;FIb6g~1+7zaG#)YY3e@+FxVF8N~y0InD?2lG>r(DvuOJlt8#C2O=QaNcN%45f(d zG1u!(qLVP1aBQRYtC@DP%*!l~<)MML{Jf0*Tod2FT49zD;X_U*ShmQ~rWJ`8Jn@i0 zIsIzin{RGpTWI#5Em}FJOvnduj)OVL&!@LErguh3V^Al!eX+(z11GQb0-PhtVH%3$ ziLvmJvnneP3$Ek4zu}r)LpJf*zT0)VRBt8bwDTF8xW^w;o;uX_uIqCoD3LoN5~gFd zcM-|R=Z?d$grNay*2exj~(ib&ZjiEdxX1zAi|NE$%uF`rZP z#wuAnsfw&|7xISbn1ZEaWA~5Ops1q~{f0PF9kDT0l%t<9RQJbT$E9DiHq$Iptg=fQ zk1ga#%Bd@mK+j&>`h#54sdheVGKq@jMwDARHuYvu9FnX%W4?3W(x$lFv4@$QlvZ82 z+mKCF#8$V`ExdO5mL~HqrB@Ob$N@kZ1QE$6rqPOV^X}9efo`n~rZ5?X8M>Si!*S0Z zm85EDQEuL6fefe(xGZCqIK~-{K41@jl=JLOG~de`hX~Q2l#Q|uO8)?pNfo}JVYs+^ zEBWkgq*aqqw?HAcQa<#A{{Rbp-+$+DuL(B^4OS31HYgyHlN1f)Imy47i?M z&dV|goa9CocPQ#fJoWzoJ!&|Q%jQN9Mi48qlk<{E$@+BT1M%jT81hhCHNBP5ea(4w z0g@rl-gW120~`**qid^EYjGW=+TFzr6Ks;rcdW9E{GgICmf+{7r)tery!JYIWgdh` zk@?aO-tPYZWeWyxLF@Guawj4yi-eI8MyWb}g$`uzK_jDC@SsKNd z%NjJz3YYskZ;y5{fJab0e;U?OaX9sx(1BE-SQ0oa)R5NJ*87UCdjfKB2LKa6xRKPf z+{9rfLxM1)*QO~}87`%Q;e*4q&PL!*2ab8*^{M51g_JC_N)=`1Ii%efkJuA|{{Yvn z3bJkLYfhR^%z`VZ?qsv5thLKG74k!>B_MEwmELk}!UqKRV2ULIN7bEMC^M3I0&p|M_=@X zlguDC?4Cfze!SJ2(g=+qjyBmCC8a+yub|@?J%1`uoX#oBVy&D`W06FmiHGFNZTYZy z{{TJe#Jif=WpI8{zi3c!7jIh1x{;!hf3w~pACSLm^I{Claxt{^3@|wzvN}}HAdz4! z&hHwLDw04s=bw7r$5Re@sTQq9!*el7R!JdUg`D|nxgZ|62R@x@X`r{cRo>-RKv1#* z8Q68fAD&0`rnFIN8!qMEkwO+U@{d^nILeG}9E_9Gf_qa;3XN~Li3$eWDuNU*^zBW_ zBd6Lsjh+Sj8Ig>L3tcc8Fo=J+p%8D6PV<(fI{=5$7H8ik5Jn1~> zmNT|8^2nsCXVb6a{xzQ&j6-ygBv9Q-PnmNdC3B7#fyu@Oap_#sPE%nzh|)<5CdIq9 zp5b9vki;2`MY|k~;~?Wcht{hLpj=zp#G~ytVCBy`h#&B1_a750U&M1VeEg#t2nnoZ~d5UB7|_`PuwlR z?t^g8%gE=c2Cas*y1a(m1_1JxA9rc#&wOL~``0|F^0U&7Xv?U#QO9!e&7P7*vMRRL z2RxSc#~7zeJ^QhWrVY#}BCP}=o(qK|L`^1m-Cb z+R#YmCRtWiBXB%!1Q2pMj(X!c%|eLz;$4NVBD84!(d0UY-72x%%1O^(V~?lSsa@V( zvIt@;EIW^tx&YWemRJmT_oD z6}gZJIs!`ME_&qu07`U-s>>?JBymKFLPkpg$6vy(OL;6p&t=8y+Q=Kuf_PO`WIaN# z<%TeM>70AirrRcT@3BhK-EHn6o?DnfP|WJ%EEo)of-!^BpUb^TEDDg9jnJdOWGyTF z`}3Wkd-WvxR(~u==Ciya2e{e0&7FZIV`J2?;B^@3?NLG` zp6G+V+2dAac7bGOlNcFNMstpY`qephNisYpa+^-Vw+$F(#tCH|Ml-?b_*RjpW^WiJ z>T12kr`iVOxwxD>X|>}qqQ-iV$C5_}fsT6BYlvQXE+e>}NX678OBN?_0OKBw?m6pL zViQdoN9H=R+o%R&M$w$$cOOc1!x-&dZYDT_U-gCZs=b){4yQDyK3<1RZxb!x9#V*; z-m3zakdUCBbM?htU){%P4D$KQ6n`k&m5EMB{Z4=Vby6iBb8b-3m0;1YEUJ6w-#?`a zHg0X(E~fQlG=k>nlE7v>d4z+2Gt|&oZsrgnS)nWfNcm-6 z+29kw=a2riK@`(F%Q{GeI4a6OWo8G{k(||LX=Y}c7CvZE8C47u9V1F!NpF{mB85!f9CS{dv)C7#dDGk4)X9EnplaI{zts9JDSF?$rv&|aK z4dm>vcw=bLkis#Kx;h+nJoCw|u#G%`Bu=At+>^ zV%$7$btxi9W(yj$(W|gr=Oa1WoOK^e;F^@kN>?gE#Z|nm%8a{Ig(_6%u6~?WmTmws zMxYp3m8AnG2e0Gws&?iGMC@jYM36H^BFhNa9-TdN$G5dam+@V1cs|r6L*_KM5wt%z z&UiQs2<%6tL)5hf*2TCQ+C0SRaMvmamVzb<;Deq{2cY9WrD^&k`#iy=ic%haL~LU` z_2;k@MhjC|rzAsfaBZWDDp{^mh2Qr^ag+7u0;RZUZ7yTX0ShaIbwF89P&3#QkLS)Y zRW`>oMV*vIy;&8T3?t+KJvwJ6`qjh`-Q7sg$s(%b$%xh8#{LxU3xmSS_blg@a@k&s8YtBtHXGS`_Qi_V|sUoBQJrwqMu#a$NA z&m<;m<7kFGyHo~@9(I-hXM@~&p0%BBzi3;@XN;L6BPV%f$mfC6ImaX0(xQ1`d0QTO ztmrp7w&qqndgDKhK3KLcW!waf9l(evxP8ZTftW0S^Z;;w{dGK0k#WDvSR`<=Tg2q- z1QYV}llULjn6}Ww(`IM7NYw3j!mwV)jN{g;%Clg>G{mejmMD{ur1Ak6Bpd>8dUNkv zb4Ey)dWn`ASyW21!EtWlLA@?m9oZQSzwDl)*or)>S6R_6;hars%F@Qf5Z}b0@IwL! z$mbx{LnhWQBCN>RU`XAA@9sV7^n=fhZXRVB8OJgU_v3MUTyq78i|G*?@h`B!r&0&N?30 z;-@m0PW9#ykskF5(k64chap?90QRk~q0*g+ZuY{is{~9+M~T^+aXknaIOucFr8G61 z5kj;1-)WJ@mke=`WI%pp4}z+3&JVfg7_9f1-6R0*i_8tR6z3k9=jmEe&nZ|8kgLTH z`uE%ebDRKq=N31)mkc=3G6X6@VT~v^5F|V{Cw`( z?72DQX8`gz=N&OxM99V~Xr*&-ipUyCA85}^dWy}un&@03I>=Nh1QjYk?Z?Wn`2PTnLli3` zJDtERZI&k)K9#9$H0EiebD2J78Shb9#}T;w<8OP2*`|obN{)Sc1Dqaz#;|i~n7$C7%J#~AmgskMDY zp;X@!L$@kGP)B~BhaB{#Oo+EYF7`xI<|9S`U#G4IIr{okt;ljw^(w%Uypk+aBzs0> z4REosPWaq;<2W7aD!6@pFMzSQ&B#?mm) zQ1~Qt2O#?U)IvB~(&1C>P>~o6B2pB_K@Lj-F`h6!yzx@Gj%&M_nPxh^n&n0ZHri996HhJ3Ml_ubCJs2+Mls2aNMoG_Sd&;W;vC zVVdGnPDh?M1^@+S0~-MAxj^SWwA*;yV&3@;3oaf-2XGyT7##lqp7gfHLS&FUlU*`! zLVy_ntN#zl&(Zn9m&E&@%z$xvLMga$?2faZ8N{i)cF~uxXNY1Gk$^6fu z#y*tECAfkYvP+G~tt63y60wd(z~z7pz-=EXI2ky`PFYt;nnpqU$>)2oKgb?O+b&GN zusnt13UW^ze=4fxDHR8vP0T@-Slr;Ml1RYxCp`N8HI}I?w;~r3$eTfr%a3z3gP_5{ z$s`KA^2u=;?IBpm#nxEyAszYp{eN86Q`~V0CTU^ATDmM#Fo2Riaz63M zxVLTdK$FcFCITh$%7geH@+vHjb1Zudiqb~1au{$9-u(|h<5M%nLP*XtYG)v|=cMLEw7(Xt3 zPku3uJxyBjKhai43SGh8tCFgtwsHLHZf6oD6xl3R?HqBK_A|iYmNb4BkI3=cp4D9$ zI(l z%JJj-`N$)V#M3 zG06mq@=b9vW)t>wNQ0|CZ1a)Nf5xf~?B%N_K2?eYL{aCdA*S8XHaGx!gU)}#szo|X z^Trhs#Gokvkid67gdQ+GD$Tp2#&U4ckgix{H?2=BaBXQ;Me`VzV#+~cPxJ53rESX| zQ(9ck$bnbv@-dXO(n#_vfI%z{er)spO*#)KB-W8c?2w}QmrogG-rVh0Je+Zp)1EpS zsIIbHIZ=|3?v7)OvXAc$fcsR@xp^@WCP1<7gf~HxgOBUq9@Wn{sGCZcDkhc)#?c;k zG(Wvp0gA9axZwV^QaFTPytt67m+D&qMtG@1Bx!j#0%`B34dyh2h{EJx4B%w-&pZl> zLpt23W-?8EYFVQ(tbnL*aCWg_jEoX9+M%42gKt5?S%?u_4f6(OMn(CU5^>kQ2=efZBC?+)IEQTw1ZA+k(N~TXI%-X?EOpdB@G6D8D!R7I45)IJoSkxV$D*{*# zaly~AsAsoW<+yJ$45q^*Jz3ir2N><@eJUtnC4{ldZ*Sx(v|?yXiy;RaQ~*YLo_N6g zDq3xu-KJW+pUgnY7B_OiHt>FI{wAZ6Cmv9f5<1(QgmBBBKxtA~-8YcHd5k99Mi~L^ z#|N)Jr>c~X$&yQNxRL(vJrtbdk7^oeXlRwm3p>caBrzrqBT^R}XTK*L`qfazBQXl{ zv#G(xavM3tIia0r5-5U6k|CKTk19w22Egh^`Rh|L5yb1}ZJTM@!AUG~diz$Frp&6- zx+|N4wx9@QSrn?YcONT&dY&`ek@!_8hnT`kawm-M+|4jWj3{m0agsS09Fu`s6QdxB zP(vwnRy)QQZaL?Vm}h``)cHy6%$BiO;7A_U>PW*#p?ZcwcHo|%tAr9K1z(j1 z{F-#ENOq8*5&`pPpG;%?^!KX0N)3vzDSSw98#qzvk~q&Nj@?aDO(DChkGo0b*$><9 zEpTc`_{VOg+#<`H&m5vBvi2!Go7W+5^A1#5$Bk9|U zk~L4WyGG(jf)R&sSh9>0*k?Hys7j$GQ@CtTl0^rODnw=Slq#!j`AXxCm82ndV<%8_ zWB2gLB}BJagG^iysyP`x)g#@lrK;S%;Imy6+ZvOW&j*a21`oAXjQ~bck-Mq=(?|;y z8RH$fG=Zj;8Jw{5Bb8&4D2OT_?&NLjjCHJLc*2o@bC6GdJt@)0 zEM_?hM{g3b#ns$Jql^>xoM7cgr?qKDroKkJ*Xm|%j%X&58Cb}VwTn4pyF84Zn5mKE zMm}8LPuSOb`SA%CcdHKIdS;_YVMy-an&eM7kV!0&FPF(U2Wah+>E4|@1)-W&kjl*a zquNLe*gSL8bI|&GQBrq$4M8GFip#w4l1Y|@rQm_oV0sbFGTkN;HqZp3K^!T`^ABE~ z4_cFG5}rzxfNpGns=fO3s<#%)wi%=>CyqvYVy+pAla9po#&PsDlaq@gaph%}iso-O z?K4|7<1tk>w(A%Q4+8*^o&Y3u>)xS5Czi35^HwF@IxIU?SD++zAe?V_myc1psy){{Z4Ci3&W8It}dZ zKu|K->BrXswVh`4B}(XYJED0N9ICMk5afbzY6BXH8RoZHS{7ar3o`Y{9k5Oh;rZQ) zWtfBvk@<`l%yG&Ql6q&;xAmywPbx{I-eeL6%Vd?~(z#}}Iw{K0A0tHZ2_s)F*rw)5 z?h8n)F`jS+(sy8X01k1Qfh21<*v*o65d!3}=aIqwl{~&?%&cI6jPC$~J$*XUE#J;o z^UNmWcg%wdss~QLN{!B{X-+#2Sz^2ef=0`~b1TMnf)8FXhE~BJN|Jc8uFWc+DT_vA zT>k*|v)`IzrbzP8%FAmjN9Mp}47>Zk0F!`Nj1KtknuOggu}SkIH14s(96+g$Kg7cs zDn>>JIjeWEqo9)5iYsf2ORI&O<_w!y{qDTveSJq2ESoLil4jqZ`C^_{3158jKA&2! zvox;DDlDgJw&H{U!12N8dK#^FcrLb&vzghaZN^Z`woGRurhU5eT2Xdq6HvaQEVKDh zMK!WS%E0-%*hq3X%JkYpcK-nD)Kfz9T8OuZ!#Ehu7$`qO!5_}7LlIr~1c!G4R7j+N zdF`IZnry0L5g8d36cS!i0ncN{uV2QxOfJyDI4JN#e`$P3A#QDzwyS@4<^b+Pl|8Z! zIH$_XG;l!b3653H=H>h6>OZ9-C?CB<3o+dt*2Do_bCB5n790$YpwoPr1Agto+r$QA z3x)?I^*P{B6fvx7PCs^3{McMD z&jjRRuJN(yMMv4(VtuGYA-1;`@`Pyx<>(S7;&P{F1&4k}?eAArm6^n>%t8#iF44Oj z;*!^T+{+=yl?|5WjmA|_@C$tj@AU6SmvAKeIE_Ae10iN0fsCK=70BFeW(S16`~5pQ;Z%ttSUK5<`SKY7PnVQvY8M9 zlKE;*cDJvnJRYK*DP)l&5&39Ijo8hWCw6)aR6&Et zr5BV1xg#n^Q&r`TNp2-RRm2wWIBPqG0}P|6;Gf4nw7xcoma9Zf=9pyO>XAp~`JQVK z1_viO>5qTqOLe_OQ!Avoa>h6^tAY*>T%1!%%HB)KG;JZ2?8JGus- zL}?yMr(Qmzr9o|XX>kx`mOFyZP&K;=KX|+x`Vhc^J7e0UkL^%B#FrjGNv=-CgqCIp zt2a(_+t34^YGx!BnU*my8)9{gDu8?74tV`*Dvm77ss`r= zZ+<_?#wm)q3j6mfDwyyHBkR+pSc)i(<;t-vj*7t!OEV1ZJ9-2D9@SbXr;cpTy&f31 zFPsYDNzMoJ{{Z#YHnTb%X0+%{49*m+s#tl2LmU<(pQnFMYP`3w$+k6#@XN_0M}-{Y z<{8ho(wT6PT*M>~I?Bvhordki@=5QSs`3ISlgbjx{KpX?Ng#91IL&E!G;{k$DH2*3 z(E>f~#PTSUY_1o9gNVQw<2)1ZSx+MsmIRQWA=i9BaK||P1`TRkO2f?$Wf?CD?(;#+ zZH)Z9fJePHH^#}Qh6Y*X+YQOwvMP_^!NBj6pFz`_&U>22L^QmgYIq}ZBZ@G<^UHK2 zkItlyDWxLj2rkt&vL(dv6@<7XvY{uE0R-dwz*J1a3%i)1k;KwOW0plEt0?D#)1Oh) zRa=9RZ4_ci@74z0Gy#gp0~5~TRaoQ>F^~rt1l2=xI<483lt$UZxc&Lc?gXm=jCSC+ zRGdopaa)A?NXJxn({fkwpjL$GFcRqX$L0<)NoJKQznJp zStLhPXLVq6fLMR}g>`7m>8Q3`w^Z^)=ad!XB~{r-5;~8VWcL{ydyiVEW%C)*>4XgE zUN&Y{1oj@sBRtV832}CZea*Wh1Iv*lB}tC4 zJ5{ekqSrz(^OYS}B%zJw5&*@IJw3fgADv!>A&eV&BVjBq+hvrNC*>rlIpiKW_WIUk zvRkXWyiuu#K5gOJ3aH6BCy+QFm1-kgN<&2?Ff?tHmgXNaGCkM5DW>jEERkr$cY;2{ z1+1*9{#zADcMO0PvcxFhk)DIpQrubWhCiEYZ^JTx4%}oPp#&estDA*bSj+Zlnl)JE zWrRl>xa1I>#yBK*rpl`mY}}hli7=Te0qx(Xr?p|pAxcp|L!;~=qE+TKD}uxS0M*Sg zqicnk$k?jcZKUu&{d`o@LRF5?!P_2DVa7dw&$UsP%tf9yB<}|WP8gqR8nQELD7A0C z;DmM#q9U=g5H|NY&pcEzLlgY6$RFe)Jo2hRI2g~bU#&POj0IfnIm={|k}3#xJ6suK zDoX{mAwXa;l26yrP@#L4ixXO0+e19BY|R~_2`(hJCP>uuIB~`~;QNY&mN6lDOpYdt z=V?x4X)(#j$36Q{VTK8X+g!-^0urVe?q3TT%KXSMr##~zo<5Z_`H!8abY)HsG5$3& zhbj_HvYak|tS!E?v4u0tE&Q5*JO7m`zTE#pma$^P5WtuhYNa?il2hi40m5bzL zw=%&6$}ZUEm2KILt2qioa0$i;oyi5bKQ4NV^&oZ!>)h5c zX-nieoLjcsZNOv3dG!@{?Tl_!CXz&mF9jQEF`lEpQBtb3$dsC7bHFXc1O}OdnC-*J zPQ+u%uUrh|V?qxy z6PH?_IT199&J~b>k)AjmNaH#8th<}1R*WPeY|iM+yn(oN z0R0c@E2@la%e$Tb2}(fOK!}a z2!I zxOC{LD{7xDr)|7~tU51c{7oaT}FcWh>;87ZH!A=T>8HC8iQP zw&W!V82LcJKU%@w`kJC&wlovSWRBt(&&wNIT(o8}p1A;$Fi!&?TCaN?7XnbRx&?(~ zH<$rPImpjm02%Gb=dBGOxHB~4ZJ|Z|hcAK2_%(wM;nuf z}U3+(eel2!hnZBFJC44miiR2ZPOBxsK(vhH)#vBv!PXKHa1p#IPXnM;IQ*JQ|)kteIhn!l;Rvm*pdIC;Sa(^EzxL<3x`P zqAN=%UGXe-&m%EmlBDj)89aQX^r)c$%-0dXe4`%u=HqA_ftg)}| zV3IA$2;>}ObmNL-en`x-N@9s&ICvu5!AQ?Tj;5RF?G$vK$Uav83a65skDhSX({y%fhA@9XB#bB%(Dcqj4LUfs#57q~H!nspW<{ ziQmkI)<=v6338yu#AJd-MsPmKR%? zOl^fooCRiXr=Iu&r`Cu@%zC6d%2?%+XyZ$Cc$HLwK-_!a^X>lt>!=<%WVH$=lg(Fc zueTvvCmelw$JUu7GTc1By)j1EAPBF>cHh^+* z*QHo{Ss~bN=5MOp9>`9$Kj!9&yt>YK*bsC!6fZU1nXkStddJx4l6f@?fea;7Wq@Yjx1x?oz#N*_+Q|>v^K=Okc87aK3~?X}1lz~W(cEJW?IzzVD#rpC$yH&djSBCG0DfF#oa5Kht)}}pq%t&)*2q)|ST^QAPB|IrQ9(RjOp>*XhFMq3kz$aD z(9)K@guOzl{&$VaF zheh*A6G&1CJd}}#*s|#ne3tg(f)0D}_|=rXU}q}vA}gy%^BGD-GW=7t-d}Q}i$37(W9#qf)zWT&%Hn;h6;>1sS7<(`-nrV`^O~18kx3C{mF_pkYLO@} zytmBT@qzD-d8suCmMPL$qIp_3UE7f0FI@V5ROp&UmMG7WC8PO`9IdrgnRz^(q+_7& zeN9U zyGJ~$8>D6@7Yt*B$jZBU@6S=t9=}?u9q0c5kAl(37zLF^S-NAW=z4w?BRhF5zEKQu z4aE*|83g|EyAh7ubUxM0Q9qw>kSmzbI!?iW0I=_#bM(lo5J|o{Qdm}T9E{5o5? zVCSejjPZ~?De?aG?#9_x6%4lWZOEB$56~WZdQ%FjMoM~IC5R-RInH=BFqQ~pZ<0w}r&V?hjDzSq^`{8sm6@ltcx+*rm|Z#n z9MWT)H*%jT^c%b8tCV9n z+qpO#bTsQ*i6k#?a3gaxv69j$+=@FW=t1sJa53JP@<|&^rr1LB6Xn2|Y%j6rjyv<~ zPh?BjzR7U26e`O!mhNMbbJq@}5J#x|DqTrNPqCtvo};gx-Z>n}xy*+#1Yij{>T{g+ zrzOKDnCz|=ZL1t35S(2y+}=&L+&j-gm_hCeqv{#c@N z(L$FD;(6ki_p20pQBd^iNhAURJ8iTPU+W00WWa=9vc zWd1cZmEkV4C9HTV%_^P11?UcP3C9@Ex2+ykib>kgJ=bn0+4A8Vg z%mAWgRO1~wdh<$6Sk6@x69#2=a))jfMvVfMV&|3~y)nV}sxv@bEzBz`JFr+7F$)}? ztTHz*QIA}DRl94HjoMq6Srw&cZJ82sFh))LboDF;llaE7HGjaD!n+)2|l$|;YGPJ zxOMVfc)?)J>-yD(x4V`xC@Ko>3THr}q{i$3e(=UK_|~zjeuHmqN83$#Ewr&+G?@)1 zT4xNv>jTX|6_kCH}tKID2+?L66KSdfU2e|50OuN`Sj6J19F zw4e~|O1k-S9QuQUpKjlca@22_#&B)!GRn$HEuG?R%fh;nHmLsqK9y1xjeM}5E@TZX z`$b{F{Sy=to|; z$l{_%jHwinM#{~eyOb#U9s&CQ07`6kb3_F2O(Mzi<*k?&GIS&J;ODnBX5ver)v@D8`i~DFnh9e|6=%GI?om44MA`c!E9i(yGY}lbNPf zjvdI&7>sV)H?6#UKzQ}wL$mQ{{H6n;$mb1TMvRbp^Xag%}5 z@TTiFwmbcUg3#1S;dtHMmecIfCSG7xH6(L_M^At2O7Tb;q>ag!4CEdL?s)g(*0ZhV zmN=4GWows0-dwj(B#gyR-Yd$Sft|kNJ?SF7ca>tczDYi9#(TJxS(ns+aHRFePSpy` z#&m5WUp3wB*}o_OZ!v46f>?6R@I|K48fohIsb(s#0GtMTu@9^Wxq1jhHepWAdHcoOJ`Y zT1gT!Br&ze?);YdzuY*fvqBc6QCvNjDgKs!S;O>Z28#+w>8@4G#C!1gp| zYnzpvqqKfZh;Ag5`E0-f0*;%8a!BiuOa=ikU=W!Vw@9tK3J)Xbah`pt8YpLTJQDd( z!f?=}fOaP*CnR>_oFfSxlpw6GSdMAu6C@ahc;j`0^b5`;YwDDP7 zI!52=R|r(BE6_8NN6JnY>P2M3G;I{SVb~T>>l_k*BSLn9SFSsA{U~@uNiyv+wY;vj z)0`4x&p%9&(0U5iP>V&*jnSzlWWI%+33=7`&l_#q#sKVpA9`=vA$1_MlB|V7EN$~E z41@lCYa-Q(nObSf$ia#>(lFhHUq^WSw-FVd>eR;=Bq&)k*WcwGIO|x&zH1!LHf3)= z&z30Xjw3Wcg8o2KtI%}EIObz#e}bRp{;f!)z8Eu(1L{XDpz1=Z-smHPKI*wrHM&aR$@lgfnDJ zRYu5*amXAG=k+xllSd&Z9$Zm;vr2<*;m&^=zak~GtUoGwJC@$v0obv23+M(-Ww^w9o(FbTeb)DHC%{Nvrj@8?OqlK&5}kD?o!*g5P1aq8n+Z+EKXPbA(wK-4nQNQ zC#UC3%<@Sb0bb$cA!18-yvZBT0oNzcdefFwNo5-*ERd@#CL$XokVmolZS zpsy#IqhiMtyL_b>8;H(x)PauKAB{0~$i-E>rMR~WvTn34B%Ez-!yfek{pG&qOd}OOX%N3KU7ojCHzn7g362(UsF=3xi#r%#nz zp#uk;j)eaJhcK$fT@$nwgsEDo&3ZOrn&%2W=6@#no*o=3Q0E@a(tY#C4j z6>-;|fSmL=G)euPADa;Jpd{iYhoK{!`=6x?c8_tgcaXtx6l$SB1I!18BL}ypKgSw! zl%=T-S1HdQ*%eicfp+c=%oOg;NhFtYc}|i_vaZ$hAabW~p~p}`=QO&EmbVDjsk$Q+ z>}J@0X$RMy+-8`9M@3@n8bTvj*9C-m=sNZG^**&yjHJ$Ll_c~uWsWrSTQQ$7f$~Pd zfyX4C;P3$UKDC(kw-ZAHLhBPOhkQ(=nHMJ*!Ny3z$?e*$-drWGEprXLl20COjDcEA zanrva=bDyH=+UyPtauGEVgjG1(}SOSn5LvUN=hX}F~Krh%2~|YOz~iVSake{db|b1 zR}FUYATtn76mG~K{c}~ODKxQMx`}%J{YE+GkFE%%y*EJ}A&AJRL1_ZvRY>DMm>-Qc z`KGLNrF4ZN2qyB>d5&Cu@p~!HKmMwcMtj5&?S=_pR(;GusZ{C)dYp6}`VUH@YiZ<% zib*qd=4KU!Qp2JA2pK-yk4m#NcM!`IEQG3l^5GpymB<7Wp2QK4uf1$FPf|P2oJKs^ zBQWh)=5VaU4^h*e{{ULE5RVTrQe=D!f9|kTmgmnk6y5;#Elv^04cZ@7s@G zYI{ipf-xP0#0Y?bLcxqu5&Om`jH$)~fx#oNHMAOJDA zUQe6N+`wZ4j=sGr+eo$uuaA14f=(lFXO~&|r{%&q~XjB@GFZdx@Zo zta94zl14W&ZDj^C#yWxs=bRpTRd!qEylb^dK#CtS0VdfQ*m~p;RQ3n4_N#l6297q2 z8$GN~lt=`6dlAy9!Etv0lIP2c0)$41Z6iozjOUUML(UF3;8tz6&RJ7!l?lEZTR%Cdc$@L^-~2GYyVErskcjlk!znW2qWY*PHOM0TU+a9?ldTESTz3NdAfBk+ZfmZ?JV#W)FSrgCN42L-RbMp*$!2prmjI!lb znkAJpo#>I%qCQAIxxbxnn ziYa86my!mK6(&|`RxPoQLdOLCI_IS!xQ;b|arT2NY?a33QP5<2f1Z`3Y4WX(x^R7p z?{zB}n;C>3B^y0Q<;D(b+iCcXrXk>Gf88$a+tx2hIR)!)Jr-&IL9oV@6po zOs~TM92X`M%Yr#0JY&~2QFR$rLnJv7%t{_GPDnW&2=+WxhrfBG6R<@BBB*wS3Nz@u zawuHQy$ou(b_+Y04dvvXUMCjiq(Z@?j31YS*Mr>En^%xr%OW=CwvBw_lEIXop#C_> z`c`yOqm8jI%<1#)8&tMWPhOqsbl(C;BZrS}Nd@rqG>K1s@sCsQUxVdLC59pX|XY48e<}&&KliJWh4ZQfrEpN{QYV2 zPjwKuj0j{&N618csVBM5Bc~rL{nr54Y5%XeB&K4{Oe*9 zxtL^GW0j>)=;5~o7;WEQ!kZjT<`zFX821 z=+e#Rfh#Ps7I;uH=eK{SKaEw5)699LxDkf?yZ19ldw_apzE7d*5s?*~?pI(Zq*>@CEN5J=@<(SkuZ9;2u^?0Kl72E{KVxo1Ij zAb1Q=7FG%XV(p#?1OfG^sJU)oCYfSc7FeMzAD9A%*u<$()9Ma+!S4G!B^J=3OQR{oyT-xjpkp~4 z=O?)IIgulcm`WW(t1CQ_1y*bTGS~wot_FR*s=_=5=g-Qd(nti`Q*L^5`F9@mv}D>F zr(z=4GWqaat1~Mu$1F>6)DNvm8%Yh=oUEu-6hgpd3ZC81AJ(TvxVw42&t$Rvm5W?S zb2c*`2O#4IJ-)c=YM-1KnW4H8!0Z+cpMyWc7+|o3T zO0o7B;;OW$tsExSG`O=}i1w(k!{mShDxe)eA2a9XJm4JE_v;f;VYj&&;u?kW6w^$ayF; z&PV0xT1DBK&)KD+VPR&sw#b?h1k9o-kxG>rz)}gw=z07_K1WrA$>ql-!^^rSGYzXA zakPvQ4ngbf+mo4ZB&yFdPNcDAC|C`OJDmFTLNYEmlU_ToR*!ob>6} zA4;m17Zbpah$Ll*c`C{yW+l2{4CD-+e?DpA2YGJxymsvBvM0(|GXso~-vD>V1L<7q z7H3T;q)!|M;#7aMTwA})SX;!S%#W^Ha3l}`01s1|zF<`mPi)gl*AA@{GVM}&eBkmJ zbiw|W5o^%@0BN1zo+!gC2?d~zMN%+Ju;GCu06Sp%=BjO)<0;RY?13Oa%3CL&o2GHw zj-QQf7_>U@ZEjCAv)WwC6L~?FcqKD4d6F*J12c`I0lDfr zVEfc}B5N7Uc5%e8TPEvQmf2Yg05~A(^!dmQ@q z`qs(^EMVTZEWD1PorvU_QbQ7! zM0{_+EDsqN?06%Qp7oyg*3wG1a6@es%rh)=>_QBIxyj`7j1D;9an_}UFpHI*RR~$3 z4duvwgoBPd)N)O0Bp0yB6cJj@5m}Q@nbD(Ce}+O!D-N51&U#hB8K)(3c6~lOzbjF> zuvp@DWz+6l!q-f{bS^rwkDDa+KT3%v^PrMQ<7G(X!x%q#8mT==>*z8+!lu%1oi3Jp zcC?f=yDs~?RFME3P8c3WG3)u%kfKUvi(}hL?y_$rhTDb&aq{hObAmI##yO_jT@4hU zVb>E2cZwy0d=ibp_kGsK9Dcd_Q25pd7CUIKa;pDzxq8OK}Xa zh6SN%&;VE49gkjW?YgwTD!PWAJPAx^36sG%1o7=$wE2`#s#*-1*gS6}GnayLxJQTs z8v%|n>DQilt8p6}Wx7>aA!oN=vt8Xd#B2uUX3uU80LC&o;w{CfPc`+T$hP9yaL_*G`Irtv4_?11^!KiW(>8=TqO~l^37!O&X1JE_GrM&1 zWU`;TfsFDpdG!?s+Z|>}FBphnft6XoWsMk=d~#Qw;1$UC_o|Szczb1sBn{6QAQIg2f1viOR;zSw1a|Tpd!ZXDW`8dc zkaq%o*CQSCj`hOyV4*5oxAaDgsu zw$80A2`N&=N$AVpsU7*LWr^ZuxNwq4=*uFpCu3uS*ZktE!2y=oP1L>XM{ynjXw`WS z=vBS4eL$`0U7Yf&+b>)1mMeJ@Jfdyc8El;AIXOLe{VK+82A~?&TXdhzX*Dmk+8G*6 z-2Uy4Am;}oBdDtJJP};&5>Ip*H4Pk)`Dq-5vI_OwyGS|XoQ~L}K4h|8tdlP5ONL*x zM!@H&#z#?~N_84c<*4S_(A`Nsq32H&X5&!u{K@D409hbi*k)sbKxP9Z`**H-crKjhE^`#y0jK`qb(zWRf_gx0KBZRe9Jt$F$>+MghlO{d#q)7wZeg zwuPJ-9yub~IuGzYdHz+LC+`|T$w;F1?w3lcz?XyM5|M&2+u#2Htx?Zl=HY8f-#U6{3_y`tJPI}L2Eo&x`aQ= zB%I)mgze`C{jO`#kHTEJu24pvEzoU^k;0kVd2OwpG3q_f^{thjRD#|(V`iF10pz>UL9LQjCpMYS2GN} zE;1bL>V-~6vkJuRibGNm_cvDdq2h+x-EkzCXxE;& zr{3?1z5a>zsjlSS&PyQ?cC?ku>(H8TB!xa#FIQx#TpA+F%O=Evo;CA+Bo`=>G;)w6z?N5NFq}i!Xs`| zgOUN~ip|Q*=91-Q)G;9_w+nLNM0bT{%6Wiv&rS|TM_hYTr?ibEwvttMmKYA$&;mx| zkbZ~%0IyYUEMbz|#~+p>kr}aW*eiqIo(VN2wd6)?d6=xIk+Q#)fDauqdyHf7?^9N% zDk?B?v7LKy5(#BC?6M`=$GQ;ARZj#0KY*V6^y`6IDG7?nE@iy7F$W-8#~ZAXuUxq! zX$L*M^VCyfONlMym|V1pgXE(iMUEB+3NL2?I_rv;SfJoAip z7_M~FVsUY0_%0cS!5@^*9F4WXTq=y`Jut(d>+MilN{=j)eVtvGp7lvKQ{}rQh>KaInMAo*U13tiS0rGT z$0PxsI&l(8er#9*&0RI5D!N&uG#U^LATg{l9+l5H2uBHhQg^$d407xKb0C02L zIjkg^v?;!fyBU&Li$io$DW@K6TZ+c24g(&&1LN`O&1PTCXKX&tx(E^(2ze!TU~+eF zVoB&v0D5$*(8Prf$izz%Vgyn`s|%&#iAS)kf}Q`8VoTwomf)G-KTYnIvbTd`P+ zw%{Z`PNSi&RS4WAKE!6>VQ5r2g%%}@GZVFjc=j2o-r_00(QWUouD;IezFSGek)EKb z?yRSR4^PIHOKY@-OL@$HX}4(KdMISdw;rK~=~evuW;aVZ#~ss^FDwvXAC55!|OB_ogtk8yJc!^9WZau)qxy>!I zS%rykb_oZcBJgw5@$FK5ic6QcyoqFCe2Z@a!=25y_)&knGsze{fK5Y-eMz!ymZNDJ zNZ}&cr^KFH%)6Bvo}(i?_N9na+B4^!hT;PovW)V> zKPmqJXP*9*t95VZ&0+RKaU8RfB@;`%W{?lMoi?8MIpUmR(X45t_ZHt|a)`qO5y!hM zPSswSI0ufk8pjRJ`K{h2*nf2B-zzqKy7%DJ>hSrYC$^R+SlTH>10k5_sXX!1jz1cX z-rdkOy|&bj)E}B&iZRpEHHBKA%E*&k*Cxn@0}Dk2#K_)Xoa_{y_#=`=Nykslp?IIl zTZS>>Jgzv%TDv?lS;X?o9B#71wk9N&c?T`+pQrVxCy`DX8%u|Y<2$XQkOp0&B;~L$ zdE>7>*{P=Nb<;{Q9%a)cSVrryeEBL8*qBUXsq;7rMn(rY=hCe;#Ih~B$uFA~t1yf{ zF@eV3oQ|glJd;`Q&aWN2Zk^H?BvcYi%CV_Cu&72ba!DhN;o=yXDanC-~ z{Ql$3dy893i7s}d%FNy5j<_9I0wmR}TsKioF0lc=g znq?^&l?w%A1FH~l0M8z|BB%1Mnol%K91Sbr$ugEzZ&C*&b6Q5^Ilyek&5#zJ6_k)1 zkW>TDMeB;O7_~4nqzWaJu$&}?Sg&kzkbTFsF)dro^R_FpZU|6?EIqw5iY;M~M9n;r z**X>`Nl9ReIm=_H_7xAPN=uNW;jUOm0?4t)D>b+{Ay|M9JQf^h1l6{TM?A6^C5l-g zQ6c04F~P^b9Q%rEtFyX683?brTN_z}^YzDn%B-p^h9J+qWDKL{#?l9Rl@%ws&nWXW zD#HH&W>i*%TH!XNvc^isf;m0$)2BUsY5`+z7F)KLe9~MdW00RMRR{M*2Pcw9&U@4^ zCBqVpINl%U4oN#n!TxlucD`qk7=jHp~tV&G`AM-BS3-)7I`i{M@;Qej;9@}&D(jF$R@}rxC{Zy z5s{B>MPUfd+22D)%0KMO9P-C;a>7KAsumcJEhpvD9c&yZY@}YR7XC(wk0Xa~4AItoTakf5O%wUN_GWilKGMLn7fHRKcoOZ6R zNgVviGX2s(Y~(?663HG6F-ajZN;8tGdG#lp3<3vXRt2z28=I?m?c40JH}KSWD%|d8iHz?Vh^xqj1~ce$#tGp4YFIa)w94$8WQ-^b+$!^fjE{e-#q8*Ph@0*$r}9sUIiNZ*-B5fy?@HfXoA%u3v@))`}rHhYi{QSa$h zp4v-gw1N;kl$Dusqs&r0Pjw)0J9Fz&$rZxNs;9}eL{>6w0AzOm06x`q5vR1fxjsWI zZ;2%Hfgq4@*vKas>Np%{sLjHy*~>K;$jz9|BPcRY_LFj4K(4GAPi}eq&1<|a(NAM0 z=v=N`V~lkl&x*>*JDB6K^WaU5wJxrV%qBm7<~SWra5`{3 z>STenE{2biZI($`nVFTIAhI2*Fh&UV`u%+>Ii|Xj2w|2*kIM>LD|iHCuOMzcNdt`i zYR$4VMb=aEB!_TWM1w!XK^Yi0;*xm&(kF2|NRa|pu2_@D*N<8S4ao1LGTp~?jS`|- ztZI>7ZZJs3e_nVMZsZRxL|w>Ljv72= zlyw~EuTRFMtDG{eCm}7ZX8>HgG;&LAxm4#2oiI7{_4lWFaz=)Du-9&n^ASbX@!6QBWKD72&jFz&g4+BK383P4XBctRFK{&_r zq@G+{PaFVwZ6?S{XO%tAr#_kEy=53H5i06TV20LWE^Q;b5hhtow#E`k>_$o8dej#T z(JXGBU{{eNofa}lW;|mY;AfT`4s(oFq%yQdCWu6$1!cIAvQ)P|_#a>K%{6C9nV@vt zCL<9QZ}ni4&N0fKe;>xTf?W)qZFVbpN+g+HA@WU^EzVqEk8j7?tlP^QMCYMcD#UxFfmSndx;a-Z8!07EFPx4+#y=lw z!H#(m)#Ohli>jF7Cutox$gLvJX%)gWa-_fyHRc2r8S8<^<5^Uu+bz;_Wv78rWs!dI z+S4k4x%@pxO3A%&%WjIZO7gx7MH4d?J&DHyJN#yShkRPWfy=Cm%(9@Dc2Gq$2f@F>__-i&37o8c=sbN;TtZ|o(6b5I%B0QB_vr3DDn|YZQM6VbJN)UanhUi zTWF9x3agy_m^fUXgOYkylSsid`V#!%5;*urBO90nC)e<$F0tB6XDpz=(uMommvWK; z?l|=xwG6N4gjr0M(Oa`N=wlLjgbals{{Rad0(yW+9DzhvHj4_0tqrQQM6IQ~Ws))v z3K)U_>@&_QDL3vxT;@_DEIpdkph_SW&;Zt_wniH#M0VyetZQaHfQNcHa3A8d>4@z1tl z5jLRDe`+#Nd(N9Mx;cCbg1WJ*vj+vP#jZR#Si*B;*r-2P3fLiowYvqna$e z1-yn434j)oJlW3fLqiTpD7@e+6Ou8UfsAvS0YoL0nV7CjjLaEPLHue0|ZhbfGGNH9`Skuk(613w9>F%i8TTMvxaYX)J!<@u+NbX) zfnHxJm6h1-XJLTDZVv~M&N%1L){YIWaV(3LHo!8Ul=*(&)1GS;S{} zVU}?tE10ck3A?8xo&oLj`eLjwD)2iZY%wV(Ztj0hf5NHCB!v{8HSMMg`?bjo;NTJm z*RO1z)o4X9h`qWWCOMRtB%HR<+y>(VJw2+qnlMq5kvd6m*FIvBw(auABSsaPGtrqr zJ4x%0)|be*k^-pKraN|J*w)2lX$b4PBcM6J7~-LVPqWV@%=0~{RaQu3P|@Ub^9CG& z`E{k9>M*;lorJMDX(0nAY3RrC1P}hTWhE&aMv&c?OLG)bO9BvCVe+9>JF(S>#_Zs6 z_4TVI!`%|hccO)iAQ)K(T=B^E_o7>*nkeU*EWtFR%|yVEs5v1?2WuZ+>6&Jq;(L~k zM~Wu^GH>}zhd2NpnddzEbruRRA(V@mY~>EVT(W7tda)-T zFa!l2=OA_MTSu5tsV5?H5L`;qM9sD*8%fVr>T`k6Vu1`IC}fFz-OGUp`@&CC z^y7-A^2!I+e%sC88RKypZwD z8%4c|W^NU;$ohkk_*Qf=ndKravB47-lYTI({uMNvOv-hV9>u0#IT~1_MhudcDyn)B zj`{R8QtVlMu1kr0+0~~u+s!3V!iF;}OW+Ce08 zETo9}aX2xs&p^1&eNWP};z2Ag9%=pYWUTP!A6LbREA z8Jj$w`1~*hL2E3cLo1;w=t?aA05Ji2ob>0Y9e*0rwJ|cRkjRc6X)*xF&Pc~S$MiJD z^Cv+JP}`xkw38(+0~v@UoaEtK_;4|t4hhMvT+&B8sW~?8H6w;d9%xwOaa2h%Lb3dR zN`^N@jzI3jLn&K>78npX$T`PeGBZ+KTQaGTjh6d^`6^2d*#4CCkX)69-JpUwcAq}y znB!r|$me!3)4xikHoA_THv#c^g(2DV7^Pw#%i0{{_2Z6eH-twb&KRV3Q8O|C2>=o~ z!8pko!R?BX4b)kl+16Oe`5lk}v#~022Rvh*pmwH>viXS7!jen}+M63%Md`cifChbq zYj-0{q!CW=#}qM6pj@~UO)8V+#(C^AJ;>*<>siy>+}z#f>1@(CBnt}I!qF&%0Mt@$s)NM4AU88w>BWVG( z41{3!&#%zZPQ|VwMGo?#H_Trw&Fkrcdsb3h$kir%)$ym{De=yibEs)kc{-+;8_AI5 zVgO2N?%7@}I_^f;xV-V(}M;ZIw0i^J)w&!nB)7 z!tMto5s$}=cdmR@4{a5$tI+*Rfq2F_W$?I#`?+lUACcORhZVjp-=7g{mYyE8ytVVL zZY8*AY~z<{RF+7S?=I4NbSE6-*U29pbdL-8C*pn9reWlY@7**a#Dx~BN4o$TGsr}&(9NF z>o&Unr>b~zd;L2@y^*3xmfS+}LUEAb604AKR1?>!u4_oUnmfs&k{ew`q`P12`Ry%& zGe`&m4sbT`D;2wP=eCmlq834Z!Xso=TI*9k2&#;C>Pt zj~45DY@{$=M#x%duKbp`VgTW?I}B#KkB*u?y=$mJr_O>4>wBog@-^7IRc62>$iI7@ zay@yFE@5QGH4+AWF9@pE?$bI2f#o;N+I%f}{*%9{I0rZ4Xhi z@IH&LY7q=;6Fhd82H3>1NT4$UPu^t=q~oSRBbx9%SZXgVm8-(ji+f(1}uBEckAeMb5^44ilWJw(qtm@?E<}`|{!IFJ;jf4E9}(Yp zKTn4C&rE$n_B(w;P}J@p0!Cua>~O>{P!wkX0oyh9CH9m501BVR8jgjcYIgVbx+T<+ z!FypSdwYoRS1Y$0m$>Q=T$=e0#h(pF!cPzAS5JF&4~cFfxBEc2m7|cfgLH1Ok~kr< zTmhe#JYzcEAMu8|z9P~Ve-LW&U(IGd()YH21|>IOaq}xKIq#EO%bJ!SnoxIrzpvE! zN={kMDb%H1`#8ID$~(Vb_y_4Pf_!@|&k*DV`wB1up!qB z0ov+LeM1`hRc>|7B53aQ3oZU-*gAPacWq@jW8C0&9CWXlj}YehUL~q^TaRt*kDcN! z8jR|xd#%gP-+}dRpQ|nG@jNqmmh!MrjxeBSxavQjH98cLB$Co7t)cUoV6uo2x7kN0 z9ff?~VdDK_%^+0M?a<6yHxS)BNW*cvxsRgKxHk3knR$=DgWqIm4gY~WHAq^s}yH9g$(nzt&;42jzVZ#7>jCb{~N|qurXCtW7Gtz4{NngqvwkpKDu?_9hf`64+6G&~~K_OV= z9HRWJ&FT14r?8F}WoUtn#!NyfR|=zppF^IYIU_r~(KNs}%WRTuC3DUW4h?BEnOu%rqgpspIRHXSIbLLP zaK3~80IgJKMUGWsLj-m{QB0L2^Mmi!ty?o8X{2?Tr3!XO_kbO}GtClOd4fxb5^I@6 zd*le4fQ(=gNEjTDIrXkr2MJvc2|`0Ipp6W-D;~_2MF&579OD&DS{Yszg*>5xvKc_i z^U2TG(x!PTMXBk?sVBbhwni#?o5+arE|csWuz9FDcCh-G0HnIN6nRx3#D zH%GJ%nH=Y*IOiudL{H@TU@pkxlPf3{?WQ$v}fjzp$WIYet6>?W}&vUkg*WX%O)EnyJV|paL=LX zkHe))aTD6iw+>}kky&FgCRE4FlE9&4D&w0%y+9X6cjKjLZzxff#8EV5gRls;i*DijfptAYqPHD=Vj z%8})y-G#)i8JbRVdC55)s}z!sq^%JoaEC7^6TaQZz>rlOk_J6Frou1ck})m3Cf;WR zh-4>f1B2Ux?0&r}(Rh+VlXXwMS~?ir&STPi}Fg&^~h&reE72!Z9E9jwX~WDWwWHaNgN zeb0XNI(cFVCTC<@g;HA?ZO7O7RcA=CEHV7T0?mR-u>Sz-RJgQl7Kg$9fds4OJkqot zWKPMD7d+>-2faepS28?{JS8GvAI^>;8mwoPVmQD#9X&^`YU)U)p>45d~#+`CkqWMk7Re-3C#j-^do8TNhBq!6T0#d9LGvIhW2 zsy%&uKl=1LOKTL;G)pT&%e2V5m4t zEE*Z1Q|88`4ab~w$Roe?>s@r@+Blyy-o;Nc8N$B6q97Ubh28$h>^*s_cay}%D4I*0 z`E1d=Hrt~E94W~Fe8&Ww^*9HmF(6g8SDd;Aald#f#g9%gnvOXZLo{p=!d!mt*;%)F zWN=%I44v2m(zU-atvDrZ3$Z-$qejS^RuJ;by9!qwbLv0OTEe)!h31OTIC;cs*Gan! zyNL>M=yBG!k*8N{bz~@12x7rvtDj#?o|yHl`>8G(NtSsqt2SN}7$B|)`A-CMgU)!( zV=8c&(@jN_l3vy*gz!t32#X)yX7uNhN3|sKv`QhBC3PyT9D+Tutiv5o@nKI+I{I~m zWwuxrJQ*Zt*J8%NGLU}p$US;-N|H0?Fq`C&)S^B($6BREDQswzP~x$Dp`Ik%#x^9k z3OMBU{JpBf7=`NzMbHZa0QQU;L!9!*JY@04dvQ*dXhX+ovKcPgFw($`6snVfk?F@@ zP-@0Jk#;2rW0elwyflB0JRj*z#U25979pkRO-AiDZ{ z*EHgtwbUKt_bl4nc~34?foYXa?31cNSk$j`^z3aNoVM@`RF|tX@soJaiogImyqb)|8UHjJci52^+^8vamCJqkrze zSjKvvY~XR~Dl3U&BkdbOGDxc5d0AO~J9D1Bc&Ol(;4>70*&gCTsQ0Mt8nGA-!AN7b zt^w`%RFW*sCT?Cksh$4qygpoD4mcgZ&#h(Ds8!@;d#THq)$N>1CKT;C8+wD!<;5k` zGc;llw>EPmE9AAS71~csj`>s5+#1l6$udFa%MwgfY!abXJ;29Y%{N4sp*sj8PJXiMO~CG-U~O(s# zLv3c6(Bz(Z>z=vC<4sg(=K;2skOEOKgvXp0M|_` zc=s_2g0`UHemVM8o5z7b%S_ig+$i!D@EoqyhbDD82ft+lkeZ!x}A%5k09E^1ypW$4`h+!#dsHQh0aMN@^U>ZGUDpuD~V%(#LzO1Q3G#Yy${_v^r`K9ms^y{SzQBNfC*M^IXyFu znfxm%P>{(Z$L1)KWyp}00ZHc>&M}i+F{G|-QxNT;X)WI2UxIEWcZbep3`NS48QYu;{{W3w6V19g zn5jseJmgciaQ^@~=C99jgS>nxb@k(kmd;o$cLj#yVDjW~ zjmi%>UL=tI(CRm5VZ}l?&#}kP80*c>e%8qZ6blCg{vaTo~kBaHFXG zYDp!D)*w|}GmU|MV0(|me@fcSSe1-}$y4k2=Bz_>s+$@h%&ZnM8#2k9^ccv-4s-4AT=gQ7(CDF> zb20C8_6^f{v&LhImlp0-q*4x7CyrF(pMP4(oLWr>+F*|`%r{2QIFd!@3^Fl{o^g)C ztr#YGWsXv=VSk+uJBO$|_U;W*OJOR&u(iFp6E~b@lLN~f=NaqU1KYhsc~U*xJ~}ca zmgG7{jtO* zOO-;$cU&BS$Rh-g!!)MY7KVF!yJ(ga-6}J)NL1&hIQ;z$Sf0^JhA^_az;=axmYBOq^_tMHet_xq;Y^fML?2i(ZsUNJi<49tZgD`Gt_j*<2}tnvd43B ziT0OM9)EgZ@~{EOz{wfL21lpiSZdi4oK%O~U83eD+_sLSEb_)Z36m5hz#Vkp_|&EqoeCvrD#gBwp?PZ+7;k^%!;-V3XSc3Ev<`IxdnUW zb6L+6tcWF&Ddh6moFWxcy!Pjj$JVb$Z)}h)#M`$8{{T`*RV$AD`&S#4-N=;rb-7_- zMH4KL5XMj5PSP&jy?`Bf!zhwCrEDuYgN9|!7>t|)>&04z zSuL)eWw$d!89S4JdGDUbrZdM%N4b$;ic5Bi3Efy9G9bZY&j+5IbDZb%q_;(QCPbZH zR|H3LnK6b3fBl138F z$XU7QNX`N6k^O5m6o~fxqZT0QJhgu@h|7_Mj1UF~w|;$3wN+yAOBg}6So6L?l{oYt zUs_w0c7WN%bRdyuPcCPOw0%xV!3T^E0QKjNY0V=^Je7 zYELqIzdLfrJdUjyExCgZ!>&Q=>sIYuK$2^cW`;&pQ}Zl}+~n`bKAd}d)f9z6is4n- zLm-bOxMFz#4(G2=Z%VSVt8Lh?Bu5@)xpEh9<2dyLC;tGgRN)4VDaV{HZbQgl%yf?C za}YjWVE5$anymvPAWG+0ca-u^fJiX94^)falq~f$0zIBsmo(5 zw@u_DONf5#Y{7P(oPH;o6d=Uu$@DaZ;>*B|LQ5K{B!(^O-;Qav&ouLkI1isIE)oRg znECee=6&1>~u#YW(C!R+<5B{|`PA6S8 zD{49AQ)dbU%1p*ZLZlTPvJW8j;PXvc;R_*5p=VVQXLd&!Ipe-~{b{Fa7j?!9GKVKD zBhNhb=BvpaznHQ?8x|3TEabLMbH{JX&{FnL)Y9v*w3hHUo8`2OlAkS_7gm%u2~em= z&Tw*ly~SYPUQEqwvdedK6|#AD?CFxKTl=aoppr=gfs%bqS}`x!WuMGcWmYmG5)Ry) z6O+draZZxvIit0RtXm?4Zwnf%o0wygIU|n!IrpUL_Arud6A>+@>zSgH$XNdXenRFp z1oh86ayjYEK`@QL@==yDn9AU82frQagQLs)xeJqS%(3GkSRUt|ant_*uU7v6b!L&G zv0;qiWZk%)*dwo6Ud~rJ6sji3t>yA%VyV77FfnfVoM4ahnzWW`@da?PqLKT?JTm%m z=zpC^8+FF$!aQn5+<>8n<<_Kq6rG1ZmH+$4kC7dj9XaMXG84x-_Q*H~*<_ZzLe4Rd zl@S@o;T$8xLG~(pR}|+QyO8W;W){Ln%J+AE|H66P=f2w3Ok&&B{0U{CzGN@b}| zK1-D~xTHU1TRtqK)@I8S%`f7aTA}{{7vXvF5=+9W3ixIQOa7E4kLbqk=Z}iR4(a`8 zZZm8~RCC;y&Z_x{xZzaGZ--1QnJqfG5dB+o-1}m~dkMad{Gql@IqEdpFW`})oPZ3~ z3cN8#{lRnm1K9S_=~}g&%$xl~0?fgJ+G|x><#?UUmwLsHr;9OrYxRw@4No>OmYK;= zN)%KNAJ{qFDhRo}*5{@&T27w^q$Cb+pkc&S9kLZMDDuSA;*(16C578C6$$~3AtLK7SnP;yxw#a)uB3BfxU z>&$IINt=8HRWYP0U_k0cL#j8aEuBo9hm8}8~eUk&f9J@ zrXV`^+X*gfOtZM>%LA%>XMdXl8ScbWY3%`lXHVm5Y%1_p3To@Vfzgw9P$NKswKpX5 zO}jI!8_GBH<1RSNI&^9NNl6gEeWga>P5XejwfNGp&_CEe-=7LEnw3rwwp;@Kt}V*S zCW#5~zwcFx&``az3}gUTAUHn1{su1bYn)MBWG*kMJ#eRz!(BPxxei;w){;Z3BUkeM zX{TiuCBrc)7ywkn_Hn9qnS6E-*hOt7l^5SceMx!08NG~@=2&zZ~k`7A25Z81-SimjzHQof8kBKc;M(n>un7VnvjCRw| z52ae63l0@qx+4W2>O^48K;f{ndJF%xqQjNsq87fWwv<<-%jRu^2TUVq`eTuoBGS}5 z;FC_7*dGw6%eGhtE9~dE_W}ZhSsl@{2)GL+dImjx#=ROKR;wXbSa2^@Ccs!Ozt+=+ zxMgLtKkloKz+m+euk2l%s}!&C!z5L9F08=4-!#7LKR&aIKGTnSKxHXcyvyv(&s4Or zRxu-5xO|q2P-gG(G|3~=Ppj~f1V;;TYXa6j**x%Kk9o99VCFh3cVSooT&>3 z^n@;NF}U(Q7*{#|iq~Sn$5#BA33d>z=q|W=z+!%vhLSFQbTUUj&wxOTYT*@nWinXRL&zcpQNkfThJoI(HSO3f$ zRct1E7Mv@*Oc{+{DS2b|tEMB_Hhwefp2)FCPMKDUP~zl{)e8KBhvZQiL)w)t=Foz| z@)I^tk*B+X9Gj?5{Ht&C;AKhQ@q8YOK~t^J_~Os6e)ZZF5#;-~vP52>i_7x7GCHrt z5vwsQm~A0`8&4&2P4}kVI99wOUgU9UBPES^Ow{~EG7(rkC4H4A zukU}hAD3bf5^oxo#*DK(##^(#G?o*iOrdyHP^66(XZsi7&){}s8am8Tdk}2WiqLMJ zo)H9kJam@{MI%vZ2@J zCSLwv@u=p3sokrd9;`j|wS!*nXsAYu8R!>1P3c+>x{Slw7@IJc@e@p!rZ3{&suo-n z+f^&0tUb;pAK0mBC7t$ODY9uJmS5}EM8;sbPxk$S z=@(=g*HTC758XM|eR=zbRa912y-zA$%`G;+Wa2~Lu`gb}zvxjPJx1w{`lx zot$)o!8tt!_mk9aeCKUX?2(IhK&5|C7UXl7$(s7)M3SX zrqN3b;?&h_xBh$>brsd}Jd>r4{!OP}f}Jq@V0PJ3)*?|d3+{@eAWS==zPA{JmyRUV zo4okCcVn({c2+~MhR5GR0>f&=q?h}}(rkUU>mReH4kGh8G@4spU$A&q(Bk$@RsU(J z8h-~JBiIPdq#)i>pObbw5NKUPWxdg;%&i-{^{8#>?nsNnBD7XqXH?K6giOC=X*3LZ zz&cw|lJA)00?g&_p@vfk;bo^Z6yAgV4KJ2D{6<@Fx@*4qZwMg3J$sFUP^IDWnzhHaQ zsLWj46urSPa!Y5U?d*qk5irsJqJ^)TRu+``DA=M%9?FegL-2asq-t*3_!R?jADzO3hdAx2K-Vn&!N=ss111w{01l%%P?1g&f_p*FQ?awuVUp z{}=^|cew-*e3Mr; zmL7|8d@li|dd&9!fb-oyI(QSc1RZ^`B+A8WilV2$!oZ@C4{J(b)N42`MVvHnT3hIq zar@@=Cn;_L(-2+RI{EYWtQD7q#H}=$dxdmid7+s>)=MK0AxUrE{`EJF))^w581am> z!-qFcEz$o2Xc@H#ZebX80o278{Z_-1>kD{_q#_x8PGaV0c?KZ6i@n-D#3LuG{Q?F{ zTtz>5&6#`)wbkVFf97)6Ek>m-cyS!kEK>jUwU_XtKmhOd-keQWIabN;NG07D4{CM+ zQUm-?SAT0w6}ECL9(*$Ss3q&qVSTK+u1PEmXmLo>Lm57I73Oo|=v9u!Amb_Yf}-=H ze*=@ewhi(mgOvGlXVU0X;f-fT$3l*&X86UNL)X8s36v_O$I=nKocN(Cs^dci0EwHd zR{34EWO9Ha%qQq_Xe}EpR-y$T6VXKappWk#=9o6TR~R{$%XxBJx=1Pvwu}5)a@Eea zX#qB9!b#Q}>3pOjgi~wU^2^3tgCQwDtP)X*M-WfacuT)Il~aV)X=LOYYfeYi;S{v` zY-}&`kAa87v@}>*jk**TW!;H7d&bn8n^M5l7)krD`){_2j5rwnP9P-ZMq{I|xMovd zr{u|An%5)bQnH$}F-G$HAqLRL9Up9+*D%y&M+9fV64uj<4p$OOI8AR+s~MRRD$ptT4jJY8&q--bgeC*1bzVd^JxqlGw30aw-; ze$(mcUKLNyeB!&}be^IbL@ph^4@y(fhJH^5MkYu}OSfEZKY9I@5~7wXK5+h5 zHY`&`Ep`8*P{{vgf)5Ff5qgH_evVNpwu_jMN%b&|UH`*O6;f`V!*?0ByziJOzHx?4 zM*&ie=I_A*^&MBcO=d2?Wdp|_F;Ou-HW}s+3k4VM>szq9Bw7q5{JofIgjZSTK+EZQ zW%J$h4wf-nKIPSTmpk){)XM`eXPBst%@aCzF_G6d7qEHGR= zSI6mnmM2E{5qV7eH=6$kV6jLO>7qY& zEIrb14E?@r$P0r|M}AcekhinWiNthSu)s%sgi{N0?mbD$0ILj;ES0dDukepwcE~-8 z7(*FvK{A2TcB?liD}l08g$tGv@3d=pKJVkSiq3msb|^-gM3Rf)lSU=kybsoS;y;Z> z-$9C$mTu7VJx%dwq8GybbTr`b|B)wEz>^29hh&QLbrd*J*At#*oxVZ^Oi7myOIL3I zFfze5(ZjU&+j*&q`aXyHvNG^)H>ygdie`rw8a=bkfS8Cs((C`dO;G)6`FS5TViCB3 z+2TW->oyr}7OWXc*A1em)Jqzn^Oz<*S)~v2fEqC7$h44A%pROdKvXW(Jin8t0ox;$ z)|5t^|4R^-rX5oswm+fu<{bt?&OyPGMrB6FcUpCE$@fyzihuncuE4MC+F6aJsg=u1 z;8l#TU7y3S6DrpbNaHvCGbjm)K;jX=XSlZAoO+ ziqQ%S6&+|U1zVb)6l@y%g0U*Xe7DT)XehI$t6X<~_X*!YzmfOStBLvj{E_ZOSJd?j z&UX7-VGxQ}QFp{EkD6IuVbu_9V8)ljnP31_6YQS}-b|mAP$L+471|E(?V33>-8po# z`^ls}yQ{tQBaCXA7x?E&0ilXGt9R$McpJ`Rut4u5q0Ua;@UC_sBHB=$Vj{qexlUs) z_!W8?CMN+o`h*);=M^-~nf1h&dg%E~0~chC)~mI0CEGrY1)TA>n1sU_`e8q+LD)ez8?18^qXT|Qtk%xgeESXZ(C z-byhC%cofe6tHI;8?Dme)q%6hG~j7oqTyR#>E1%K{81rKd!|)7!DX6O78k;)u6QZN z3Bht)F{wH4Cby-pauK9*&GB-%d&j}$wYv~CNx&;6`0GlY!iAec^%!O}k$;G^I5ur4 zd3a*eCV1qDxRLC$%*HAFmN@-k8=p@`^$cB-Z zchZS%$1!MS{0!({`PeH>f|(~uL7rPfJ35di4p|i1zp>@E$#L=8C6xz3tv+;X<~!U) zSwchZ$9+Vw#3Sgxz~4K`{W)rl8N}BxlNSk z9tacf@xYd8NcYvMyL#j?z18VyZFv_~xqyE~?RjU`haov2&1=U}^;OpDq7X%cWtl=P zrCq+L2Qm)Ek5zcrGrBKqUgFDVPR6NMb*>HI8DAG7a_wC~;`@WK1p@EBggo4;Qy(+H z+OJt>hqk?(*xv}mV3M!iXFSATAKkuaxtlGZR1bI?Nzj0*g-*ii8o5w4(w^)@>*tt5 z>G{j*_wY`)}L2rshZB|wZ+F%|2{yaPLwVeg+^KSPV-3e3)SE(_EUgk5@mH@h=C z@i!%@Y_ym%`N!f;dqt{I3)O^us!$wbKaExtH;UIb91koLu%u|LCRSaa|H`zY?3eiW zRA==s_56pyrp@_j!$oy?Q-j#I^{^IEZpfqYfq)d81cTkh@iQuh1CkghekG+eOWWDG zB7^Jt(AVIif7=g9HT@)qI1$dER=}tICwD4vn3t`K{BneUa%tDPk2k5(GwSrxP;ipf zw4gF~Wue!7H9TLAU8cTEjy(U ze$U6{5k}AC7E5<%&ww~kN(e3E{pv#g9ET%4?vU4A+CBqmygK}Z7 zYkfU6Vo3i@vz>1|{MO%3>OYP%g<6wrOjq40IqZSMn4R;xw}=_iZV1b}%Ztm@%)y_7 z%zph{?)|D~QS@Z)O|x;sIBL*gWQ>WkjV5=SUwe3u6j>R)zvXip&2iYXPCAIh=&tfq){&@Xv{WSz&xwJ%(94=dw}=`+GL0>|oI%)G_NA1`d>&E)4oK!EKOmdWZ>xh=1qf>t0yA50 zEKb^c%aUTD(VD30v@Kk)l;!qZ!2KKz;4V3H!-Ok5n*_t~wyW`!tv!W<*YBEpujXj5 z@vqDayTCE#DyriJqA7}5dEWWRZ?dgutaTVEgeZ96rzL9l8@4y@oaM+h*YWc#$8y>T zE=Mjo9;2Fp7Htq%4d`i$&XX+d3qA(ozC24T?cZ@`_Zc@jxaGFvppnhEk^0Do?+E0t zw*HM0n)(9#JNr1*!BbD?rO%8@f?B5=TXnlSiO&%}!rGrye3C?e`SV~g)31^?>t}*6 z-$kRa0BX2fFG385Ihx$r(JP)9v3OUR{n^DgHesS@ZW+**jlXs_kv1@=_G!N%AzHJ@)Ipye^0V*Xd5+dEGeY zD0H05K%p!BJcZR3DxY9j{lsCtF!#&nMq}mD#*VcWu1CKkJ}dL21V}F>QetHw!A3I> zc%)D_0m)@zEwQlwZsp(q;{oP@*w3$Q6I4n>2`gLdLZQ3^BvUi6%36cs>dnV2jH)+! zbxaOKNfHEBx}d0F`(YU?yagiX8PWK?rZ~6xwUswTvZQ;MST|f%aRrB`2%8jKINpd@ zXU3$=5dreZE_^pEYk2QwE)!L&_phd13IkSud($Itvm6Wjvix;ahBxfvfM#_y>`(B7 zpYPOz>&5}0H=eeRe$Zs}gyhnz2yRccIB-2`>u-Ig8?N(CP>xN*OsJMSqOpZ2mLTNt z#X;_d)uahkA=X$7K~7*t9jBaK*au93ke#m$%|?2ECn#6VJX{avf`UzLEJP*ooE^{y zZ#3j6FUUW$iL_>lAIXqtPd+}o$o~QEPL!n~;4aNcSTQx08U{B+|L?!MgH2#agCJDl z{`)YyKn+Us2l1?7nV@L zT0tOHoA&*&zOCdTV`J~ONf!Z$yiyOZNa7DzR_|Kx#(wtbPW|R{!YGuaVM@me7pzv^ zUo$ATh8Rose?nuTNjf16{^2S_AWH6cU9<8FNVCGViUlUHQn*hOE5`$mZ#?cWT3OdMRTn;%XMGZVfD zdyR05{i%hkvY#8E<}IWS948Zp1Y(qrYeMce%kp>qS{|dwS($R~6!<^L=;DiV9x$0$}qTVwIp48G03)Ebn`> zum$)E`oWQm(heB^y7aq-!Iwwm(%t%2wz|e!d)2&SL8Uriv}Vlhz@EyxqZ`!Nv%dbAt|xEH(X7lQWB}`iMsUT zZ&OzjSOL6Xdc}q*N9nvBka3`k8BW-3~8f~ahH(<k(g`ir1TTD!yC z>C%UzMZpK0BClpd!&apNq7)cgB&a97@(i`p?GvHmUk|z(J*No^0rAf?Md*6mHFegxtPHzcCFJD=m z9ysmHZ3YbZi*9_@r!}VG^XiIEwZ-HL}QN{-GCmjK*&n;cUIxe0Y_J9kq^M5T17$n>*p#sgRgvhqWY@&~D7QSw}TpjcD z0aM-@YJ|7%iNy?f+F`p<1g~wzmFq-|Y)l<LUt5)}#`?l+yGe7fo(mhvh0 zwnKspWOX-Ol1S6Av$MJz<7aw#(8GtiqwlZj;{JG7K4j_m<%BjpZU9O#1uV^LR$m-_ zZG;ERhIOSuY@V4gx@XKQGa;OSf^Cav>Z=$JK1 zurb8qi%3q9h1;49K}%eL_~h*iU1bh60g4Ktky+uLeM$p+KTb;CC|ou$|4;b#pP2_% ztsiNj^21Mj1x#l@8VaDaDaE(jbNHwk<6!EBNfd)~#jtQcm3BYmmuh&U!au9)A3Z{IWrvSN3DoB_hPRyi|PNk`+zfrfv`&e39k&(J!Df&o-S1mcREUQCmu6CI3EWYzG@Dh>V#wxlfuo@fiv79CBPvotr{whXDc&}rM4btz1 zLV#dBiYY7NoOZh%rdJP zP4W%6tyPv8kOJ72>{weNm5wLU%nz61P3@bs#eP-1?eIeNZdhZ5ILzP!6ROA^+_=5{ zs?vug@{b>-vQB}M?e~pUiWEg0E>*doslEp5&x4;b>}3*LwqE#W-dcEGsBLdu>p~ad zrm<(rn|I^Rxf(AQ95b)-$o6XIAaS8!Yw`x?f}HPM3v_U(Ah$~@3mS>bjO5((849#Q zJdKJNqbBpHaH5ha$wZ1kLLr+DtqGhxBUo)pI5mPfJHWo!+;SdU z^8#;93I(BQAT$@4*#ux?>{zpEz4k>%RMYKi?~cgo>|Yay0;?LND)jFbgN{dzht=;g z2gKuS6MR(ZE0;Z1GjDMjc!CMj@ z`cfs9ux-krNZMlLtFd^YukbSj3%jd_3mq~~DEJc%#ck)ejJ6~}I)S(#-2*37>8Z-V z-nV#1U5k#5_ARfD{|?V@58EFPge80J^{e!&5E*~h%eZtV+r686=bw*1u*s3-|Fcbx z@&02S&Ttl_AK#-N-GqtzSVmLgeidx&4a3hFZ{~&;>KF26Ntmn93Ou_(%8Kz@giqrZ zw$R48g)3HI@`Qc2mi(JXn+_c>lEXUF6!9tqTQBc)xtxa#liFx{e)!~f;nebE`(yW) zTRsNdFQ1%8oeEa@3Aq=QFHTCXbWYsK`-GMPf->e;OI~0+Hcp((a^ctjWBhQ4*9q4> z7TLTLya7Ebb8S-Rv;I?2Tdn4$0;OCS9-k%A` z0~<^E7=ID`f_E5rGu3p3KwyDSobwi^F&oMDF3mS1oduiP~9x{ql z>_eGkwLD9Zl^22(v8-OjwzsAiq?_s?=hUA2LU_A8{aNsokmvsZk3rrSGxfA|94zqo zG5_(dCXPt9vO|4MZ~bRW5WJjJhnkI+v?Tg(z3c#*(|8+(U!l7gG`*QvM1@C1acDJ~ zltFyGKF7Ec5PE|OO5bM{9|Vm}2~>ae-NVigY*prcufVI^MZnj4*h#dg11Jr_uuLOU zv6zi;%xrt?Ds_TRW3|szQMnR=txq*Bi&QSj^;Td{-ppmKi#~^3X&>1;3_YS~3jZ|> zb1zkWS$=l5m{W%%nN!tgBBiGb?yO_Q;JQ8KJlBW!CatD_)iBv7btiSAn*#@QsmX&L zB@bok3_%1x*wsjfT6waI42@K)Q>tu~dz|6DmG;0<0~PVXg4=yb8I8-8xh=BSX`79= zlwb5_e0=LPff zqYM>U@-Cgdyt?v9l4~Zd@;uwf;dOc%n#_?Z+f;VnmMOkY=F# zlFRRn-!&C^%05>Utp*LR5Z9(!;dbYeAEmO1467_*^=3SmT^l2VNA6zVyF0_xk&_pD zHb0pZIz5+_@p_(!VT-?YJ2SQ#Od*abwLVGNt`eU(y*0buGErr)8B?;eoB8$XM4fBix^mCA;hSDK?|(dvy!k90=ljHCUmZ! zB|uJ-6IUmD-EEjSP$vh+`38^}F4Xb%C$%6EX1YR_B3+lioB+sQSu( zwh<06x@pmwG<0|q?bT~WsMs{v;OfRrH3{`=${&B`iYIb1JGEvqvQA{d$+roW(BSYxnq40_(ll7 zp_eXcEM@r4zhlkxXHFKJ)ETJiVYN>9`OoR>)72UE2ahm_QY2M;2`UEm(@F)EZ+iWm zha@C3fP*hwHpvT`%bW}(-}y}gpoD>ZZzBTBFzD;57nc6<45KW+=#Z1MmG9y)LQCCQ z3dZg3S$R&N=>G6^^-F=ZJmU9qn}tz{G*LzmcPX&kFbuM~;SP$`s8<V3gt7jO?S*GIc8=G|Dox$dL~jJJYyt} z05Xf<>vZdL`B6`+|C?b}XT>{IZiGJw9ECJ3)=PgJa{@%rs|QSWf-H?D*JLCZ#&yt!fZP7p1`Cy&`h$_t)Qb% zphD7Jkp-gzuH=YA?tmh(d;rOkUR_}6vT&xS@84L|RvOyq5M9VoDu~1!IV-E$7}&n= zN`+Vf*^@DJ_P}Pb#ofmSYAFG?v5yNhU73dIz$eO@Frd225k88|pGUeAmnt~gWas^8 zMLH!L{+VDvLv7KDMUy8RZMrOi)orslY(%JacWERhb(W4Mx1CxtrT=36()QZ}l;+J1 zFFWvS_oSmbr8vKqm`qjpG9Pqx(=9_>MGNUTB(dS%Rcty~6kEGquN#Nhf?WZ99^A5_ zPOHc8-l58Q)tG}v9>NO?1T0~WWW{j(>#x-W?>U+m8X!a*U*EB7+_~R$%8$~J7)L7H z?<9wJvn&eOQ9n1AC%t+2s=o)*)9EGqi$aby2u(>uvcRY^XiIRL>d#yAR^sM{-+?#8~#rv}H zXX(lFLDP=OYAwK&`FN7fi5N^YI6>dj$kP}t1JHl`V$K8EZT)9eDM^-*X)4Hs|?(lrlW(`%q*SgL((|;vBfg|hp?LsRY`@VWS_#kfAW$Q`F?4Mkm z*0$5P-lTqjy$%I_!4Q4ZNVon6U{lf1K>Tj#8VeB2Z%IwNy?Vn#g2fQ_!$57exPI&y zzIrX$H%C8MU4NK)LTU91_E(BvG=?%MKXdU^4hRu=(xJRyaIoTrn<+W@TW9Ab6-|CH zY8-LPWdK^&y{=gR27P(a<6HSYciD^Zz}ADtHJe{ILG@Jq^2B2J27X};IM9__U_Y3` zqx~+C@La3(bv|k*#Cw0uyeCI-)JrjI9O#oTE^4X+CM>ygEBw-2V`Zkb2}{|u$3nH( zo?N{(dS}AUP_ln^euG%0++}Xl5|zB38O_4x(D5f=47@MvJXbF9NORX#{vObEu-a8E zNAR$u(%TZ5dEc}WIGvg^oa)&r5dAQir!|>UN(cy8+-@`qK0Y2o^1)kFBxw2 zEoKSz1G1JJe=LvZ;1eFdHcmc0_{czqHTFTTc{>K!0yP=IUMBh6OTEX#k|$D2s(?>nhld#O@b)^P9!0T3cps2`@uO zoEJ@QKlaKF?Td)2{7C#bCqOlM?YWzVgiL^)G;~;GP=>nYZCl+$4Id60w$0C`q1kS_ zwKc2Nc7e$n0v}VBvR@33X$b8|x1@@H6FVHR7ao=OxPiQX8Lx7ec`GnK$u>QBv!%Wk z#F-^g&9Do6Si9Wj9cK_6Kdt%ur=s)5-0i!<{-c!2!I!maJ)GoK!9644rLs+5YHwdP zR5<7))3l^mV`#h+uZ;KC?cdjB~nQt^T z{ld@CJuWPp46$wUZF8%0(4TEviMt?f-g!NWK!!6NW`)x8Q%$Pyg4|c?5t4|T3kJh? zIKI1c4i3Zz7W`$S=a*dTVwb1msQQ-6C)M>oK+4{@###?wC8vJvJrL9IV^>C7%w19F zpiJ<9I?Kj((F+NuowJmN6-%I(x}Tg?H!Vmb^bN%KgJg%OmEV8jwaDB&NdZ# zYZw%`>H9pqjScmMWHiNPeJ*E7Kmk5__ISTl*-)|TB8bQS2XuS)R;$sgqD$#l-^7VQ zQuPl?kmtE#^}8v1*L)*kp^h&usC_l}cl0pL+(hG=S~X}z09S|Cik&A1Bc-xV+qr9G zBXk0`dc~D@MvU@~*un*5)9;_uW(J3eI?}TL^PPIAoegy)LH&isSfb`Q`yp)K-M=;c zvBgwL;JM==CnCA_9|CQb3}hqe1W4F_NDJP9)*iVn2e5=ou{D=tc!9eYraomroAEIA z97saZsjk)8FBw9!rRABE`%_FAoUp;2iGO=-_PQRbkxfuZ-s!>DS8M!_ihik_QuxqU^8ly6m+%*0W7LPdOh9CA{u_UC`I zp0h&n8%fc5zTBQMUF$-W1~C~)azTRN@0=%EA`+!3>$FGx+trquZ+BIMw+~n2bj-T!uQqnINikdOpVJJU-~>fo+CUL$21)( ztoeL*G?RQ*w=3I#(OnX`KIPbL&b5t29r-8Ao;^)q7OQqYh!QE;gWnOwuSjf0*pdUh(e9%5If3eb zUK;|hLizMXAe$z1=yT=yb#ex8uLtJuTWE|*wd4Fprim(V%7u(i!9u4 z!00{+E^)}+Jm#=RKK7U$=zHbnE1Y2{#O?kme3}(AkNf42(@&DN#?+YsQdq)bGWdyuV@n6g#>pC>?kRXtiy?sy!Kff}N4G z;6q!Y(U7pYAwx!>e=lV# zQbot2Q)a{;GKlv6Ugt-jH3DD3Z?u_YNa#avhKq@1e-(0v^{;0VTgyW`MdmiYZp|Z$ z{w|~cBDiyW#YDc}o;y&QQZisx=y(%H4ZlZcb>3oX_KB6mUuVP7F%Rj?9x-1>r_%_X zoP=z+tksstPb35E{%zr{I8_fc3=96MpJ_ceYNt)MwueV(hhd06CwYf|4;(naU@t6p z-Wm=?uC|Yt;1rM}b;4b0ae?rWr#z~wNBxry_FGZ2NrxOTXAkBcW+cc<=Nk?7nYZ9< zzTS-5Nn>nJ{I*JZ+;8FZ zlOJGSMl3_Ja-ENZ8rWD6{3IuLepQ>e&w6{nfGOhuFt;=fMYqLT{;kM{HiJs*NVW<8 zA1Os)$5^WN>Jm?#qq0haODv38?ztB%(y|u1Woti}2HTLJq2(O+X38K}|7`qV_bTaC zrho^WS^k&1xz<}Oz1aJ9d#uPikK59`@nXJ`NX)O8h=%#9sfP9Bt*zj|W}?HH<9}mF zV)cKW)F{Bfgj&eyTVKdQtz(z_?bGWUEv^s1m?-v1t&tw<4a^Kzm{7Yiv&K-*m^qzO zObst@{MC)fL;}iJ#EQ0YtLsu~G_Q?C8NL)fxcYm5X8O1`Fi^yPE1Rz>eQcQv{b6`Q z4g2?h0MjqG5K=hEQ4W%$$sTZh@`C=jc01dv_!>?)39}|;e%Bh(OdbW-qjby-49(sF z{`vJ6RW{fXz3__p!NLHzA+Hbs3N-`%^X=sMCGEL|DOg+FFsgWyXQqCHXE@kPT&N9l zJFz87*wxELbTTsio;0VTjlYPTZ4TcnE0lI#RFUdtDh0DVr{OoO=Dy`9HD>SCbMJai ziMR>zBMQ^%j_smR-+u44vdb|lm@QOj5va82_-o{WC{{z31Oo*Zny7!)m&SZ<;}Dc# z&!yi47qL$#CgKQDR+0Q&4yf+fi5*+F6DOx}Zx$W5=~Qa*MU@Z8BF;&T;VLI*C$zHd z=idBnHH>Ro#z)wbnql6(;Zv0ftf$Z1((p-ioqgqi*VPdTwB6bGFz;KeEw47l-T#=b zfATzT`&V^1Pso=HQ9&sD4S&cs;fULkEV*<$cE^A9&-%A&qsQ$n^OGDCO_SUUF?pW` zS+WB!2Q{H`abW~Gf)0rI%%cJSX#p!G)SKaJ{ z7>SdPNyT@Aek}_xv)=Hv?+E%piK5a7dbRF>Rg}uEDhKnSgRuXxevPB!n24Zvf~Wg7 zqKMnM^l!gsQ;;m1%8+;E*8(cMu}^7l_luwez?8xBCVobmnbWGWwoZ+| zb@rOYk!JTFf_1D{u z27zLp0^Qu*&}HM>v$L>9WFERH_mT&frCYwQUbWduyDywy4VU5VsEjR(>89(rU{ z8W!cxYON82GfyTXBSnhb{;;)5QSEVwz!*AhF-^F4gtwQhQYNYh&OUvFRQr5ZoE=q( z={CsLuz-6^sEk(ce}G<%nM6uQeW`sJloTwVhnmZ^mUdUK`yZeMnN2|5_g0fr<=jfnKnz`xf~); zQ!Z{r!emO;dnR}e4CNJkMl8NT z$^&V#P_nS~1bwTnVk7vkfo%lm#n`dQ1Ekp2D8P)e${Dguu%8ugyqZ3nVOp`)d8h9d zAyA6>vwl+FdNU1>0Ngyzjh*H~Q9~W^W}T)QTDL~b6CFWcZqJL{_h6wJU1a&y>U4+b zAcvh_OL_B~%)&mzp^L|-Qzv$2y5q3lbZqXdIYulXFu_uthoxcHZ`B9crwp?&e2DaDWy)sS*&dT&6*CMsgJZ|=Os5bbtZ7%;dr&&dwZTM@7|2u9?=ju zyw*B@__{*r1mUju=Ede*a5;yA;Z@ZpA zMbbK8i_F^s2ILz}w5~MBC8T^eWlLd! z0{?BeRS~T5)JL4R4~C3o16tgFsRzgT3G)m?oI0^(pUS_Fh^>wPVCko9$PN`g=XW3jJgcjUeQ? z9fx75P}J-*=+*B56}z#aH1)v7u1q8WxzhV{!!lSh`(?yK5%oQNn^2;Tr5Wf?taYV3 zFMe^W8?W74s5>?~pb_N~QeR8W995l*2n&M>6REMP{{s-(Uocp-tg z%3$iq*)Bh$6K{P9;+4mKbUm@l!!u65L)43&{y(gtJGL0jEv@t`_B(EkX{vGPm2?0f z&wwS+du#RIEXaMvs&RHfJSE*@TzZOOGIz5Z!+OgU&b#Wu`E736tN?_1H-uoHRkUOn z0IPfRf=)qUdx#NBC_ek8vIzF@!>68)v|;BQg10y1(PPWJ^n6BH^C~-7)f1Ea1M7;Y z6=)b(uQK^q8;toqsYy|#7RKxyz`u8Qr)jllt54o`g`nU;K(I_OwtLmRx)SR8GOW7; z?}&zYSx49<^Tn|^3Px~~hkUuk?wE87Dpl}&GzT)$nr7S`85+*&h_wNDC>cBz-m~5A z&0C`@8C}-=zQxF33pwwv@K8E3uy$H96rGrnd>;`9`%R`NL}faB!gI0;-Q_|HN+Tt^ z>9GxrbJsNSc=gq9v2s@BZWLc)|?!YK3Tmh*t%gpGDa{BH19@bpR&v%G!h zZM$~tG67zR4W?;n8cec=t8%C+^O9!ElPSyApz-at*@ny$Ph)!8_$&>xbqsP`HzUY9 zBk=;s%P4p4LiYp{ObYD2YFA&ooBMJUdH(Q5sT7DpQBBu0uI5hI@R%Xb7E{dfzMD+; zX!IQj5#C;R((82(m0DC6|0QhimBlW<&V~v8N{G=OR-a*p+P_H2_wY*L!oZeZn^_%T zCAk7dMaGd*O82BCNn4ht+L}vDKg_#dCh9Kkl8T~7 zBM2KU|7!H8C9J-I@Nx-;VkJ)2vm#TpoF=t=9cv!hOaOj_W+F`^$A_N^Ek$MuHN9@; zr8ERn)nF^H3}K5w&$knMy3=K8-?4LL$I(r5ASHSr7<3gq^OYF_)%EDQ-UG9Ll`f)~ z&8xDUV6=fP4o*yvSI(>Z^zLAdmz*XOVW~wdsL@A;hy))i4jyzJ0`kr(^tLvLOLTVY z*xlnp_=cNH{I?KfnaT%jKf$b9;RSLmYcNZT;4FdPj6a;oHc9-!2E2~5EK&qsD4>YezgC_ZvdCzEifVTW zKhw98Uii>KY8Wb7T{I9Iaym`Ua)_h_{#d%a;O->h|p6mgQpYRDW${ZH^sa;P@)zoA4iY~;1D5UPEb(WI6#tcWa$u4wS=8)?1 z<9zFT90@FkS@=`ZfyL4{TG0FcWcPfTBj|E=nf_eTlN>Qfrfj6&Ws*OQ7;G!PR9E@- ztMKP&fFz0vl6a4XkK{W)76U{qzzOzj-?S`33J3!%q_2IY`Pem3mNP`F%~L^~i+&6r zJKDi)h%lETD2J!nJ(mnT{kfZ4sDlH`BR(otN!37Yd?s=v7+*Bf*s zs1IuLOxGSP;+=L%TMfo4`)iI)k@;4^pc;aHDv*37?R(Fi~zpwo;h8QBL1S_ z@${X_!6}QCr=VcX=0T=W%*gYFH+H(|y&w>U_T{gAfnmDQ7h`VDjp{Q5S$eA7^{HJ( za}IqYGzC1*gup#HF`%szYdp@~9TFtcew(8|99Cc2kAWpV%~iJbjBpchw{k0X2~qhQ z(@=o~+{Su!>mPiiR}R(oG@E$DiVdcgf^ivRtkxMswHWF9c~F;iv@UK07pQWed(@KM z%yYoP2);ad?Q1$z7;%arFt^KF&|69+1% z%HgFxfLHDyCpo{EAwOZ<=kl8{**sSZq+9TyZHeV+h|NiH6n@cMPj(3KOsp7UocJ85 zC4DuBf4}9oI&7hju0(7V8rbe|d#6942)o(&a6ThgxFHPs2`lo`T#r>Rsj@tCPM3W0 z1f^arXK zTp0hkt5ok+xiNt<2`s*8`;WdGxs@wcB zO83dE9_Q+0Np~%9lom{RDLMR{>sVZhE=cV%u*IdjvHN>h*{ozy>l$NF7qaL_F~_f9 zn}-7Ki1%TTtG@8_%Y(vl|2m1E7`)nd_{Dunc>m3Wv5i8%zYybY7p}+2be(7*r*sCE$%$uCd#@nn=3_t^BG=t+;U*1 zS7+Bg#rVv}$BNmue_xv4S}-GHEKt4}7S5TW6Ic<-!V(*^m_Ty&=vK1tJhu=rS;g01O>XJwo!?KzD)aXL z6w2b;g>4tw2*5Lyg{!!L2dBuFT%RXaOS=d)AjDEa!ZbG)d11*FmNTr19Epi#wKp>z zn=%jkAu@U$JE3A>x6TRpBI?yeQw)a2^Qcv{ywvbMQZ4VQWtXrrj37)UBpMrKVYJP& z56cA9$NngCPwY_`B%Oth2lmdG7k5xoiWd&rMt>m2R?D;f2rPAnqrUtL@&)it6=I@L-T?B3mu&pW)-nGRd6a z&p(fI_fbX>cy`)S%?ql}V%CjrDLk=SYIcP`Dv*kXMwp401$?(7dVmnAX~^}`xbW~y zsWzV>Kr;xx7$LC=8w^v)oWSE%Fw0dcuBV21E*0ME4_^1T;#<(wlW*1SCli?bk|}fe zCpO}w2>|iyx0aQir-_aGI0HuZjA1UOZvYLdl4!OGVmfnTc`l{j2eqA;>RT7#L z593DcOO2u-=?-uV_=A<+^R5k9|1*P35%s>X_@AUr%r}{9;@hWGt_nj>3d9T>jjzJq z6VpPAZyq*4BcmbF6gs!vv!W?rV*g=|E#|E#ukYz?j88en2RAXwZyKH}VoQ54Y8ZR- z`DGm@1i+zJ~658w_fWO z{phGIc{a{N)5v~-Szl!|Qh&xHQ-7xBk>cPUT2Xp`dM zoa!c!L;)TP5>p%7;GTyTZhsYkyIN1ex3_u_c?o)~1Q$dLY>(QIV1)dF8xvomf8wXPaN%v+U zXPEf#Lb}y6PU;lnA9aB_tIB}pM9zZQ9N!XJkSGviN>ySqtCWr-1BB9Dy4#uw)|*wL zj-gr&)!Rw@<7A#lJ^{gr{83^lG)!_va2Wl&=4(wQHx!`0?n)@#iSYE6a%L|!JD!J31f)>cS(+{%5<y55dU$cs6wRl?>r7ahkN3@OA<}X{On!Ysr{M9*QW01qE$;d)_*c15(yc~*LYu@$b zaC-}YzuGgg6N`1N1t=e!@oV&5m2Q5lzcbV8NSfjWq48h+#_K~p+)aorQD)>b< z=Lc{r;F>@nWF7W5_^ILC^&^{R{CotmBT8S?*?gGD8KRs$Vy){U>su{kndX)CX$6Do zIauCo=TDJ;^Hg?TF_NZ)XM&tWiD=~t-AIv+^pu74Ynsf9we_qoh`H#JYFxW^L<&0zMu1m+YEUr-Udp86K9sMEy!Q8>+zv|c_jv`PHEeHv0L}P zQ~t%QozxX`J2%K8JmpV|sGAf@<;Q-_UCrP*MVULs2`d{h<#%0^_Tfspnzcap+fcTv zi;56+raT;yc5O6V!YKNm>}bBxd!xX|T7#Lq0wo1(YH7LzL`Wl=o_&YaPDo3X&JfdJ zf)IaSC*MXwe-mX2+>nr*gT%a4|Co%wiNuyr7YQ&QKKO?atuA|J*p zQw>ocb`WD1h_s=_-d!y*DaL{yW$?{rq)ED2QKQ5^&V<3D4u@N zZ|F}L(Q+pdxhD`ChxsVh$_ob_I1=f=YqfYPJb=(5pN4h0aAHR!Ncx%gTdsi z)AvTfQxS#s5a!dl>*n!h1&T=2-c$Jm3+Hcc2Q(q4k&|`Ud)RFPP|(XGntvZvl~XIc zx{yMiuH)i|0f_vuZsHW;2aT+V_`kEzDa&LD?F50ea4O`6`rWU;m!lo1Vvj-}2GM)B z^TJ2JB2kzlP=S)q$^`YYfpC{q24C33Q#Qv&5#uvs$Tj=6iXi6ZumJDPGPAUGFg0MZ;}OSezZ zo>j7+H`EeRiD&K_XlrFkU|UTdKe?8N9oJuDyA??^AWk$0f10_RI%C4HcdN{3n9Gfi z?u{BlKFD82cL~j*y}IC<=%1wOzD*51-xyOT$EjI(#MxVW?R>57Aas5MFlC*_m=As zr?wAoP{F2+yU6WF2=SU8`!K7$p0wK`j{7Pj>aBL@;7Wel%aQSlWFMwz!U(Ep1_M@a z$Ew~`;QcTe(I2^L8q0XUXmek+K!pflX+Xnzk%w1uuDcbzSinM<^+F4`nQ(yZ&;$@3 z*8a5Pm{o}Q>|olrouaAe8K2PCgrlstf@)6vRypl!j9Oy4n+g-L#|hR!YJYvlOralF*MZHOw>#Y4<6(o_6< zHrVq$Fui<}W#zkf7(pFp>)y;+ZCg)2py1Jwynh;{{SR0Ry!8sNA?-JpZNv*RAFu2d z(G6U?+2wrls%e9#LqJ zb+OkTs}4y6KuYEsn>u9ym{PTx9h23mus?86p(x@^2Bd4Laj`dF8QviS7PZ}&d3fzl zKfR^Z@t(wTL5!2!HW&R!ZK(_w5v{u8qLu7`ol zRMV~j7}x1;d5YN|_@y`Bc9|DdLI;UL@^uVD*1-aceJxKkAQ7AZ1PJ^70;K>X$~5A< zBynE2M$Lfra##4vvC#=Mr&USgy!nQYkcL!vvY+U|GFOL*!&H!h-m{J4DQ4r?3p<+* zHqcx=lWQ68!-#?pcOvyh8YmTfy-A^Qe?r@`z+GwrP}PRG8;smXWa&61P87+H(@1^* zhkToH2)p^JT_85rk@2GIORAG4uXU!@LgIXR6|YlpRNxE8liSOe?Mq@s&yEjDx)1WttW{Bsn=ai_oh@Tp+CyYf@YydSxh9&+=N?2KqCKI_gUg?zkJTH}`@t^te| zV5++bCq3B|C4cGyd0fac_dTfpj^q6wpC8|8BLvO53g_HEE<6!qhJ1O^o!t;C=kBrLh>n#d^`LqfR>ABo33q~!W6!<4RGWgO8y5@7@ zB)6D76vVzZdCfyQ2H1)^NxWb>g;#9(yf6;0_w9X${#yej(j6PjRT$4jP3$KqvbM-b zP3&Amj6&K!n%v>H@mC=6zjFJ1%J=I^Be9$hlvAX8NvtdtfQ@+-*{(fMsCq)LO4xUjH zNd1DMv8?^@D`JQyG4i?6o1Mwkz1eH-ZOgya1(*PjMscSDmqBn)^QuO#CUCx{qy~st zu?!G23$WYTc)BCEd+>g=!nb}@l4OK8Hn0){fZ+-+CNjw*o>_LDJZh>l2$u5}JOkFT z<}cCH@B>0IMBL^h5jv$^J{7;hAGmH`l7`s?HTxq4k%qLe<2sZAj`VstC%uBDsoe|p z!*5UvIsNmBliO*boLRJXB@wuVmPH3MD_9z{=>ihZFEQ!oOr@jvotF~#N(WnLWpJA? z+!IzeW0+Ws?{55!IzD<}zw&Eg{TI~HzG4M0$2gF%pKuwZT;|}?g!vSb2P=vs9(0~$erZtkDTmOOKb5V zR}|PaE(rT?5azqE8iBI~T+OdYn@MJg=M}%DfUWy1_$PFt{h0@Uz8qO2y*}C}Mm$#p zbaa=_Wfre{$+#(Q(Kg0_P;xhNl@Wb||3r?THzloh6vqmrEXjK0iOn8MPQGR6BI*(> zGkWn;!+6E`_EEIpby=+{nX4kiz%S@O$Wp(xLFeMbC83tzUKZ{B%53tTArO>WMvUk&)9I-hgz7JzRN4wQ;u6P?m-a0mrbx_)Sdcb7` z6KlUm*IdbH}MJy`Fz$y+O4{lmc)#Rt8^3$(NqC(!R!5W);tj92qH|NRt zO6P5>iN_{lMh}KwZNOnP3XeKv|07^nU)yst?>&>4br4|_2zJj_F~YNO&sO{Jk7F++ zz5>Bp6McOiaKWC8(tDw!a-KwGMVu$_DD(F3DXRgv_zN}`hm;4#hOePM;Lv`h!~{mz zO`KkN<9m~l#STLn87FH4WBC`Cg14&0j!Iuu{v)u@y?e6FDIH#}w+l$%*_n67<``sK=99(ER<}1!s-DKg)uV6;pl`$?tEj<(|OqT zN4~#c{K&R#lp;uOs#|FX^!UBgjue`Ad%TKKbtR_gvtY)lOiQ8UKqD+g$>RkwY4RRn zh>MGs$RMh34r7CyP20q6_Y)z4oTNtND3uStL|^qCx3?PAP-Tt$Yf=|sQEA=F+;#WbY*ATmLhuT8ut{dK&F2y63Mvoj!_4LP_4WgK=qLJ@E7`=js?<&W4M3;Vg z)!k6po>V`K1O|&trjLYWI%EdvS33N9aGLsNl|RTT;B970*Ups7!FRXW1T%2qL-*F} zxt=rN=MTufPtNxE(G~I~y8Z)mid7EAGUb`f3*|)S>_yxfTtp%8orlf3gZ=tiL!^9j zx@p{xHoX=>(#{wW<$P>m#HPAA1?yd(MfyBtiNB5=c>LzR78ryc@OZ~R)_% z5|&du-E51O-g0Vi6mtz*4Zit{Z$=9bv+1u&x3c(^R1I-mw#o*tr3%j!-kKKDxsosJ5BVVzhK9LAFr_&)% z$kj2CnK_=-a+6Ql==cG`(gzd+G7@T9mQWpqk7;k)rPd?k#!iyBB~I_rSbVSGVuX%!TWYh~ci1 zOT=R`H+iHFN!B!~I<_xl8M7=vnCvR82f&8apB_m!{vs`;3p3a`55&wS#;jV#3DgVH?H)Yyyy|w%%V_zZFMWxN~N3AxUQD73aNu| zwMZdQ(V&k}a%&RFeo7(rzN>}Efwrza=o(FW@57&kf0LuO%-(kQD4COr5S=gLNC>cW z$k;%oD2w3!Hsf1#$XV{0r&Qv z`^(5K{RBHlv0E*tF~;QSuC20u8_+<=V>r@vFy2h{)#naZW7*btNm~wWA_pCI!dhkQ z$>=so464aZu?jjlyv-P>c+uyR#YR>zd4#NpgH9WF8Cu%F%-;l z(@g1VfTH~pjnze*2D;}Cnl^c0kHK_8yN=2|w9kph9y^sDce+3hqv z5A6lJAThtQBcEdP-&sx2#h2>E;yLGq2Gt!|Zy8|spGerqNU^ea4>Z?5SA1n4pC|JK zkYR?K&gI9-ilHVs*;Qt0l5ZoqZF4J*W~eanzkA7 z{yFuAJitam&4~OIr`mdpNp~>iO(Lt1S}_-(?c! zsU2Ndq#oEhZ}{RpD6Km#P%8N%PeFv`QG-VC2Z4oDmoCjl-p(+dCqTEltq_?NO9eZ{ z$2lg4nuzA(wNGw?T%SgJ#YubSv{-GrdZ?%F{Q!N6i*iwdnBM&@m1ix}B1& z`+`?lIWb+JZ8rB;o`fmq+!`yEp4oVKkAAo;MbG9?O$%;HPt0s(hAkcTc1E(>peWie ziRIx7z&(yM@gn2|VoWrP?BepOX@-i`1!p!ClYARfxZyTV3?Mp|5h zNvm}uQ3U^(gu6u9{340Qp7`rs+vd9w!;8;0J1%qeDo;KHYs)(~vWKBKGFZmu6IKGh zalWJwDAq)@8}yLgEa!2Ha^Sf0_7AMd_C6L;M2_McSm>2%j;GJ$3E*^Bmqo!g($jOA zMlJJt%B=xKh^Cm};L&aHoiAT~_1Or71DbpJ6+s>}YPSVVpT}2v0?x+vmg~;zGT5m< zx%L%>KY2heN!41?lr`57Yy0o{{iN2X#F+|tzkk>Gn3=?1yIZ-FEjVP#tDkBoMmT;K zQv4m86wB1~9H`%z6*sFR!#2?}iC)1dkg7SoT9z%QVU8$7mfld8hK}@8GR`o7=GyG_ z`6DnyJh<6X1$1R^?kb=#(km1{&NQ=rfO__&POsK(9rU76ccRO+>`j0Q_-JobEk{q; z7@8br!@O;EHp_b!Mw3r#Ou&IZJ$0bXsS2%&A(AqxZvr2#T8&-dFrX)g z*G4SIJ)MD9(hMG{(=W41=o1 z3kVfGY)PGs1!AUb;BtMPg|=AQv7-KDYqZB-NvKUPy>al(VxT-I&?Zupc^TZL*AwSj znz$Gb`r&3@6oHOT~`|!uSnIYsHP!q}#lfk6q7n2FoBWe48Vws%tDWtmo zV$;s_aQ0;qic0W1OtXrPmlC)|rnAJ!r8N%fiylR>c6at7C>_9cScf9Lk?V&gX<}FMCv*>m4>bl^0n`fU+S0vup2_L&)0x!AL2Lti z^F7xRKJvYY-vkc!NvH3_wbO4?BDrg;`G_d~_Slc#nl-%i%t>mDoF@6Z(JfdS$$B6Q z`uznvRy!e`Y!borgrTzaABwOaL zYdi-AF^{A+j1>!?u9f48>EN+B#BI*PXvF-}B7LM~)IaSTv$1D0wi0e|wyGd;&PvkY zI|bElMr5#kK}g$g$=4=X4n_}!2UjgA#r&aNH3}DUc9aF;^Z_k9*U>qash*xdd9vS8 ze?=w{PdSM5vr8t@*!}31`PcEKSxYAy4_c6$FsrghruSH2H0}ZFbUY>km`yO5E3TKR)R3zf6xUnSL zRBqXrZjEd19?#4}%yc)oDZDp(>TSS`t_BzKUPd0WO!6p87h?`#$I;mf+~$__-#BZi z_UT6_EkH&fQdU;(OogM(X2WsfAmXe>dXiIMLvprn!q6^-(L$EdLL#2#S|p|flQ_WX zX9Lm&+sY>R)Fasl&IiX>52n1Up!X?1qCI=Wy;K@&nK*4f0 zP~)JXh5^00nj~69iK`gXB)v`EPH}%J$M5k%QdCgEgI_sCed}vO#OWF(5RnzE;1K()Ot!Rfw}DxO zKUZkG0PgImxS}_eI5y=C?8HY1bn%F{nPQBs5=M4%;?ove3=8l|jwSI$F|Q7|Jd~*s zHKoBzp#Ut^g)IL^@YR%ESH@-MThH=@a|F@n^Sg%9XKXXf3u2BAXyMYGXH(yKzYB*9 zV`^`3{KvI+yZ3d3(+&a8&SM7Zw=UQYrWNqh!|?pBN9tX4QydKbqLiXS9$Ro_T(h^0 zT2wj1)V*t)F*N^s)t;t>UKLiWj5Lg}$Ur7-iWQ8_ji#G~JDL=4|CS9X-0B$6guhO< zG9jHP4#f|w7rvGtUt}CcNq0@Mtd;&pFkhXTy20(^yPh%%wHumdv zGWy_~W@;iMQoTP{pof(o_8g6wuOBB4$;UYUs{7YY09Hv+?XdEq1eeyyMLU>GAvcABTW&-+LOx51w~zTiWWC8q|Nr=>>@r`|P6l>xk( z(?;w<*!nuvYlWNnwXui0K1t$1`6**b<%yC$?g%DTLm77qO4;AV(#9U2zh&3*qEZv-TU{u+H-J| zuzUeSHIjopnls)%uS^*&-o-f@3E;|69#DhIngaw%x)g!62N(5K=2Tr~>qC@o54?N< zo-S9`#F=l32{+;eI}F4U6lFNf%7q>RF}`K{j-CkI(?|5cY367|FL(_i_AM|9SK1NG zEx&R2X!WynQ*9c^tVShrdgm_lnQvWyV!^-JKd!$lmo(;jeyYAXf6VwqzgaTbM*ACY z$jcd=se-@v#&13f_t9s!Y%3E#gr6kXCV@d`HSItM$i!_ADyY< zJ*G-0j}*MJcX!DuTftTOn}9lcZB#j2@tuV$>QO~&+5PTr>#Tf!@4TQ@K~2XVHUcOKa1Vln?0Fv`|DR$(5VAh z>RAyl2d}K~ZF|HSBy; z#ZR`Y5RjbnIc%~X4qDYSFLb<0k@c?buqjgWV^|Z**ntN(Mw*vxb71&C29ZHUOHL|9 zPyqAMDF*2=^;I$t=Le5QeFCX`oi+elZ`JtD74MAHL^@=p!5j~ITs?_GGm)*$5kNvn zrjhT*yB0$JF?0~sp+ls^h{j&_DCBocrtgxJ)SE?{AD?8s>D=hn`QAT3vo&0v>^Loj zMSS!0v?)g&u`yyudBV4FJ&khR83LB!*I4mZ$4|$XTtkIlr5$Bt!^W

zP^PTS+W3 ziP+-@M}sRf9hS^rYntO}2S9seo&T>Ir9=>ISz6&ZHC&mU&AaYblQGGxy5n%nUwfiy z{3GRo9qClGcR6AUc}#yrTP`+E9c;{1ky+DWovZsqs%=U(o6Lf(AWj4yM8%h06Sk*^ z$rSs_>p;AKxor;YX|o_VkyZl6fW0g|wx7n&P)**ux$<10A(1D#EdUM5=7rfZjajc6 zob^%Fr~cl8DnxV1@>S8G&!cQWuG?P>{+qOHGCU{zCTWQ8aj|}u<_VrZdbfx8y{i>s zTzIC_%MW-K9=1)bs6zVUN8%be9SQO*DVe+07Ge1HoW+}er$q|nLdb)nO>Kii0gZX$TI`_-?ZPJtS;*ALHwH;X||oD8zsp^ zXSkA<<#dZ*S%tXJ{`;c`#tk4_Ihpj4zoVtRHf z^wJHylC|#bHWoY|l8qq(eYC*3aeNgjc!yYe-g(B$j?@OA6Te!BP z8EToC=30ux7@**U7YAtWqI5+Ar*-xTh$T>esw(`atK))MDqvS*pv+2Kp(9J&bD` zh_Ndln=82Z*Z6whobgSE#G5?T%H~-I4&5>L@V`GY-*tZPjS5kEc~N(!bB`G_$!31q zye&CYc2cF>Z0Xt^n&>J+BSaXEiNn`+@Z4jGheAz1Xn{$F9M><0A?N287ne1H26-=J_U};il{AQ8( z7c$G;LNd4b$xKS=hPb~nWkuejq%Jc}5BSAgwK}Ew#LwJo)$%@SX6sR7o4n{G|GpCn zbT;Rh>)gqHFr!)?-$1ep7A#bDztw(sFHYJPJjR93@tZ7~a1=~c)B&#p9($L1(tH9P zp_n{3kI*d7+S&8A{O<4en+uU5t zYHnabpEHnCuYkvyu#OE_HdLlzGQJPU+(oh608sveFC$1KLt<#kXM*gk&OA@I+d**- zhi1chu|`HM}G8AJEjj&D<3I8n21B90lRUilq_ zkzltWE!j2Lb`hiOj@OG?$FP2H$E(V^W-s0QsHB18U z(wL}_>uV!Vj;LnU+c;MgOjzS#TMT;(DkAo2SoqVW6VR`LS3-kf<*WcKoW^*xNrwkX zL|Obrs@0k}r0(yv@%7;5 zG1;f`;I|KkmA@vM)+;ACK{@P}m;S(n{rz^Y8BB3+kSp=C(}f?Xm`M~>@LFZq>WJRK zUGX)RhuMh+cyoq-X)+!1omUy+A6+^N{N8aQq!Qat5XrsN*ajAx8(niK?#kmG$A+q| zT-3b#T)6YvzSCaZpD1C24E>A7@WyJ|%)k{N{JJnWYmX4<;yur~W=dsed-`nwNSh@+ zIwbH9=FNe#nvrzmJMZz)ZOQUYnH1L$`?mztA7_5p5?nJlJQd~s(7AL!^^5b1@2}W) zKLo6sC4QV>A!IHSWtU8SP&pcgQ~kKtf-g=TC%f$o^r_?Tu8^CBT^}=fsKmu9Br81y zSFqw13?~Tx)Zs!1#z}hU=xm;Xh0It;RgCw}32SoXWz${W^(G_Ta~`F5xSMBu95tej zkt91ZU(=Hojhvy18?$xI&~H26$y6i`yOfi4d3WY+lBfH!N1Cua;ciX$5K}&LDo0*w z+FHuM-rH8vPn12V67z});^RA9-O{7fHT`o~q`1@Mhw<{FYq>YZ@r$epA{j$)|Hi_E zT%gdV2m)uwQpbyiiBt=KF%YA5e0--sFvf^?Q>t#3o^NP779*Ules?aluCC@4`M(Z6 zy&JL9nkEO9^r%FfZ`Yjhuko`EYpgIMPMc81XXlk2h3qoWPSC?`HZ!wjy6f~-94Qah z`9FdV6wZ9T{kY%tTe%A$aAX$-V)`&@UQSwiXZghlw1C`qB{TEOzx&~%RN4Gw9d_+p z1MsQ|4vxfH=Je!(OkunZyOQiw>bUD$3#&Pj*N}9Df}E#AYsHbUs8VGNk;2dW<~|a< zNFG-o@i${L3eZzboYYUFsN1NeqIB8HZz_vV0rDpxf?Qcsf(PBYGPBX{Wz$vCQ+^R| z8_oH2KRqjXh~_$kW`(dBm$TmNzV$v7$o2k?1?`&LdQjD{VQGV-irtowe&IaAp=;Df zA`S;0=Ii(uBf~dJC0wXnfw3`$+yX5zi0YUte)Sbf#L7CYR;8plH{N#dqdYU+5K@b4 z9a9alnJX`3b))*hqZ{-%&Q{|u&5MV#HuOI8Pftg9QX?bt>k)8WCHj|N-tWL#+zLh~ zJ1DP{XNb@_)&K(CkcbP8=iJkE?XPK8N!M)>!2%N!N8-j%7>C#0ZjK=AfITjI@?QE4 zU0EILp@_BiV`YJXTsFY=2Duci;-O3qPv&%IdfQ6q?$#KV3({4>F~KzK#|Kv1q&w;6 zy5|(R8i}<^vD~y2nm@?A@*$@H{Z_oOjHGt+%3T*DD{p2B)EpaHMtmo&eyYQCcg143 zOgGGbnlQ@qYT}-rdW=0D6Zi3#uSJ`Dh@rOFJMG@r*gmQTvVuG`aj01(cR8sXP@)!| zEvjyiDfUT=4wl)hOa1cZ0*`Sh$=&0XjH{SD{cz@t==pn1bb1%64T+bJ^iZE{KvpbV zV`S@WD@q21spu-hs#d|PTO6rPKdk73L&yOEI3`M#*M2l2Zb_bIBNoC(`&lx-LFaO^ z+CxGHMG;8_K}rHSl}Y~*P-`{IEb}jOj{1VNL%`iM0+!Q^gu1IMI*~Q0_C^bO{wL~` z9~{c*n#n{a_0)v%URK8JL53%V*#3VuV{G22g}Y#-`TG7Tp+E->?iW9vdLqb8dLLLm#I(#`c>nH8jzP_QZ9uqUY-v_Q5zhH(@v?Z5XFHp zw*IAYEI0^I-!^hv;E{x^#1feE{MF;i$*poydjViDifkhb2$TtW$%wZY}0@1iqlyOnJa- zR0G-B=s_SHa_w4p7AZq(jU!0Ot|j^<^0hzSv@*ZrbN(9E{<#l6ES7*EvKKFRtIa_A zh1tBhmwQb}$`q5>Al_0YK1l_(0X9-L9G>}XoBVNDFBIx%z4d#2{W2;Yc#7 z9^BhsB*xcMzQ1YfvFQ??XO0yS{RLm+)>xkvafDtB0RFxBniE~eC5YVpwJJw68OJ2q zURvqg#kI1pEhXyUp)39)IW40tWH?SzMHgz6Go-HpYcx&h9Q8)!*OeL*$FV17RzD31 zVVQ2ULPjTO*HiX{Olp;k7!wyiADgjj_2NO2)#L!+-^F-LVOivR_+3YgUK4v$dcJt2 zv{HpAD7cMv#;HW+r$}+|h{zy=>^mkZ#`-LySqNfOIs!kvJh2@qmsutwK8KkDjj&u8jeX)o096id)Yw>$8Sf zH6je(ftexzFpgu%sE5;#9kB6DkN3WAqI9P|K>gdTOI zS?|C^(A-Aq1Hk8kEwSx;5?*x`>DlWIF+eHDAF!kmio=y^Lwd*>?78CJ(FizjTN4qt zB2~O@08dnV1zdO+oee~QeY^w0gtKRQJRILjqKSxj7~;!tmKpV;*N?Pz(rEG?QVCt& z#P~J1ku*+7^=Aut|Bs^c@TdBJ-#Ctp$O;*UjDyUN6;Ad($aZ8Fj=lF*Mud*TIrcij zu}AhH6yY4lEPIx+l2IHZiSO_H{)hMD^}g@xzOLtmR+n`6Rt7-7U{TA3O>~D{S@KzI zP-~Cn0gurib{E=gT~Zz#?qqBa9i^+V$TEa{E#K*IPPL_xtU*@!byI`s^6v}2h6;U1jYjS-l-}tW zo%VGnqe)F(%a}Y0O5Zb<`N)--u@wmgJrFr*7j-xa&_qzn?_P00w!T>ZiV?5CC(|J? zyXdtS@r?xm9$(vqsxvZ+$O0sbIc~Ks0?!%(wpk>%JhxCb)<$pt6C}%ympfItdLoAk zei#&VpBZA+VY-u_?*p+HOX~R>w1V7aIn1cyPNLV5W>7Bj>v(QU>}t^AzF^K>q2>wt zOT<%@QN)#Wpl*>(xq5_I`<6WgTOwZlo$-2)Q8n1q?05r+E=iuElEE(&MhHswQWHgj z87bk(_;n7zS7Mz%*Qc?M5>c+(93I=#O6ud8hN*%~-Af}&etabl>ij)(jRm@UbT2C* zyVe;IxJz;ap1;AEYgy$ajWmOIS%ht!`ldu0FFD*jo-5LGclppTDo^|+%ktXmD0_+{ zc}e0h3*^`z>H6|*!M*VmX5LR^0HuxH#kwtY z2j+E-XAK`{s)su(l{ubvh05T7WckW-3mhG^ z&DnmJWm+Y<<~f7m1U-@yTj~06J)9$QV=cCg0?v*KaHZeS)*zKIoi z`=;3d_k{ARi@|>sE@a1zet8oZDXm>BKy6-!a9+C|B9?G+>9xH9+eiNkf@1zhW+36- z8N@0>DA?vM%-N#2jRp_y9`9Rf3nfo>OAvMMVn`WK1tg+O6u+y(?+%=-i1FM-45m-} z(io3(j|oypn;b?0@C?aNoO$ttZ)f?{V;>$pS3j zUP)3?$@L@aoTnj%1EwIPTsx;w8noc-hZ0W=)X>Y=+fme~NAIt$&?G73o#*rtA0XGI zRrdIA*hb9XxqFn4BtF-x1P^ovK6hNc)_vBCeGJDUs2Ali~F(?=aYs=XxkA5*W%@3m56)E!lJv!1gae;b0-bnGi4CAdrgfo`&qkx}wq1v}f{^&x z%Q@p_%iM;%&4SSig;f^WWbp)|^e>W-Rx6xFR%9^)V38y1+e}KBbGkcs9VcT(xSge_ zov8T2qx+WDRyt~tHXB-}~FVT#oA2m;$ zPif7))?)M5k`B}KW`@W19hpGomobCL;t$ob(E!AkT+_pYPm}%=uh~ZLfZP=SX)O}p6Q!vwt^W${^U-9Ln?POquUmk2?5*rHamrkzc^wGc^IgxqXZY; zl?#>kvFa5rs(T@+$EfoFuyM1H>{aT&Rz;JO(<^p9Y0FzV@+f0vPLM1RhmE2o_A3ik^+_O{2F=qpVub#o)F@ z)HA&`DfB^;{KjLqll;p+wklBz!aaajq$(mqnb+bgx?#eRE?xo|yek})|08?yeoIvF z2Pt{j?}gEOaxfzib2#p91-5pHrcf{2*73QQ9|TgfY;>(3{}3q4*ni0@bKoh4niT5@ z5`5V8V_lOwpJNl~Q9|6aHMtNeR8Wky4k3V0L$}giPvm)lE@3pJ!lTbkCwuAsqS94uZ*h_)GyjXV8t%)1>5TxSIhPKK9M1 zqs1$FMEvX$gl>iUm4Jn8Tx zGHH1DsGtjE+5G_DxVhC|FKgIYg7~k8-M<^Ugny zQE$Vi@}#W7jfGE!g0?n@c-8)XF&cnj$KuPaADGrOdPaqN)dpnx3;mV!e9!Sb8>Cw(8}$ z)EAlk193wc>mIYxt!M9`-Fh@5Du1wodWwE{Us%!&Yg)j6=zN*sa2=Qj3l3x!4TOhI zw^nevfN*U=yY14e8ACk1E>#_f@1iBW5bYH1`STV_IPtVe=vG{6PBZRE21lH{t1-)F zg?L8+u(#{0$d>^&^4)XyyiLh@4QE{;;+Jm@AkG^5ST1GG|LrmQdYd! z^ssO6E)IlJ$j!g-{Mm&4lfxS{AgFdWH3OgWm~O)9Oa~H#=>u5ea1O1zl=QA1)Fe+_ z_?6C#Y!`V(D|JKgo8zzd7n+)S@t}O$3}+i$@Kx~AfYLe7q{4D+ehE(lS!TGYWbX$x z^w%aY69fK11AB|&@xWG1=esRB4t*!vu9hW-=CjlyB8VWw*@GOsKg$wzo-Ry+jza?9 z!ii%96g36iUl~r`4b^k|!k>i~$>RuQU|54E>Z_z9}kNV}>zN<#2({(n_5ap<7z_W%Bdf*R%heZ_YHocMH9J&|=KBT@7y#519-5 zC+eJLC%bnK3QeFPk04*{(*GaX(+*yaqPfc?*E)_-l_MoQ$+q+Gzh#lu5Uc_&)RNO2 zvn7SIvinR6$FgTjbO_m^=WRR*TtrO9PW7S45U?>xzNxt zsj7m1*%Lwp9Ick{>D$X)PuT+cxBWl1osXUYZ`>Q!`unRU=*?ZC=KdYymfiPyTJZqS zf46LiU0PXf9}k4?Je*;7cW_M|P+8XrI=%k3&QL)!YI3-IZ~}k9UyPTvc%!nHWg5HE}y}M`_zC<0w_H z)9Utk!dI-|U-apI!$506U%|li7*Vh7LAFZJpwj;1NZUN|TBof1)$MkEdUbW;H7OPg;i}2kK(J4sexowbG(oN zJ5?^7?q-gaEK;ye=!pAWZ^h_A_6H9_zV7eaoS4X{GWy)&NfXdoWI70V@c6i4)Fu~d zX0TC0e=#s^*e;zWbrUhhF_vgmS{stZ5V-~T1LcOWYq&qomRg7;C>!i@fHx8!ZO+cr zPfNURTYzRwDYEDAyNM&eww|lcymMJiSE_#qW-+}354N)-gisL)*kJB0U=rf1;tTJ> zA|+lMKcOeNNVnDNwd~c|x6ceSGWwVl#|yVEZHuIb8T#&yZiUy_8__51!rm+9T8qbP z)#n09RaMbvP29%foS3CQzB}(yCxhtdd+ei@ob5CTq;#1ozRAq!a^>eaXVZr$ZbF-W zR{Vg|kt7^|iu{$?6e?t)q*D4e&pA!=XXM`gO51$jXwerB{;i%Td5~8U`o9r)LG@X- zsbW%MAB?f^aRz?yOJ@`dkTfrGZKX!bO{wK7_@mY&kg1>7S}rwQqT`M*PV|7;GE0k% zLQJGvloS0|50ox*X@582CUpPpX^J?9SGbNsZ4b>z@84`(bWDgH2KiR3O;RIk-Gr_5 z7||PPjn_QH|Mcc?juPo*n$CYPEHns(nmuAj>WbPeiN1}R{ZArzO|(l->$n}z5if^` zq67y0GQ&%-un}vtJghBV#;-<~_McFzL|Z=06iB20?&B1a`RL&0>=UA35X}1qwr3Uo z@kEXhV6`GocTXB?(K>$Vi~6G) zDyv|MmZuvYf=J|_t4~JeKOC;Cj$7h&+VS2SEt2u|rr`ZmVl}sWQIv>d8fC9ejNS|* z>7@AIiT8n-y$Y7mKU>^1e8w~+aH~P@UIHTB;AhlfdYwca3l3TpYkZTPLng>OG)Ee4 zdjvbRUxLnsMr7bsoX*@YJ@qbBnq#6-$~%pQ-{r9{9$W?!_>59O{(@lhrQg9Jhx^7+ zU4`YH{UsyHH)mwGB0?5F0MqRwbvvFqp!&y3Cn&cVC9lZHaF5V0s#sN-H8?)8c&nE|*KNpMC_^WE3)o6{k9CQ{LpfN!sQ)gV$Z7^{sMq-DW zDdzi0H!lpAKaTWtq#ar;H>KCdp*3VFeL5fzzC6P8V|o}VIwvrGr-a$iuVOf;QCe!E z{)qIp4Q!&5KClUj4GSf2Q>}zQK_<5m_}rAcMc#lIO3waT5F&OyLg#h-IDDiTHn%f> zy$Ic6&cyeJnC6adlp2kuIY&uRQZcH0yn7gICp*cNMKh&2=(y$@o&HYXO0wAC7HUM` zPT%;&tK$#^V=UAsBCFCNhx6-%cmFH(YB8`YVgpdxJAHIvsImU*Px!<1aHoBN94x&c zv4}9FZtVd=NAK3C&AUVH9Weh=bn(e?!^*6(XIKGSWRtGCC=;nIQIYi(f`Z&pBDsyr z%Xu{E9Yz9Z?zs&(0DT5RyO%}WnM}tku9SaORz@TtG&f}M+Jw!yCs44SP7E|oO3lbp zPA}i&&x(RG1dQk8FBv#c!7k)Ne@|i{ka|N-Gpd+*O%H?;W|2rR?AoEu zd`kWcZz1ZUetaC+XlPPwK^v0nc0{cawg2_^roX2ycQZ@_^qSJ%`afxLnXf4hn_qco zZ>+MT45DBA+v%R<#xrnSCN;;v(68P!;#Lk$vJ7uIh~Mw!`xzZ^pln?*n>@D@xhz4R&}@Ej3wZOY$`QK?qT?Dpo@Q3IVj0LJuC&${cc$01 zoIxtQj&`#zDBN9$0<{?$gBN(q>0s}4!!*f><8e|U4bn2y%{G6P8u8|TWXLCOQ~_$M zfoYo-t`;A91v!;qgKF_%dyA|~#yt>&%;3v@`#=%eL@Fil2C*nt4ceOH#%@B{ie|&8EL9WBEoZ_imitU>sy_LpjU>$YRRCEmUh$$#|)vW?4l4A4w>V7JL@(P%Q zuhy?}uPUPT*Rf1e&x`25+=31grh-Uv*;&)VtH<6a6){LULia~Pl*nY@;Ufa?uX6|h zajEtt_g*3M(#azkmjQ7WE(19dVmoMBE!Su4eOFf`rjwE`@=Js(AD$D(y#z#%f{C(9 zGs_#ff-JHR#vUi+tDI3Uewc%T9jtyfprVYsjH)wOM0D+aBG*c1?h@sAiIxu4C_uD@3WCZYx@98S1kPw3L2s>Lzmb z7pM1Pf(+IR7pzk_oN4w11>{O$mn z-hgI}t+IkR{j-ZnE7ZxFz8L?>X2$YxM#Aie#nnBVu^IQVr`k@YaxsRaa`nOVl8hR} z0~Ewih9%eae(x7U*}5rO!t|wl^|5o}46BFdQF=#&qBO}a_j8nr72WHVO$d-RdN?5? zrl&tC^r1kSksih|t+Mgr(WIuZl?!HIWwaNTCodqv@N4dt5-#q2XV{xnl?qPIfB!C} zr6_8!rqArk=`L#ygVyC%*B{}K#a@!(!A%D-`ex2 z%CBA3Y|g?ne8a8wmvWCV>64{!4%tlYX}hXj`4fkzajB&zzW1Z75~lPbRY(B`mqr@r zt`0fLiCKL=;@XnHgte|y~Dxx`+)-jSkaJSb~v^B05uTQ)n_dn_Zwoo|T^%FSOtmI{5%6;NSO zUtSdtqRxN!*okEDrB=P^v|h1ZIdWSUo|!1tFFZL>+M8BY70cNwtf*{mY-`~-%3FuN zjskU2-w|>Cvs2U2)mt2uqRig8_EE3Qf&wzd$o~k%=wCvAHX>~@D`AUT!yJUK3Gxhw zZH1qHFP9Ul%XTM%k^;W0^bmIMYybT`DSqU+*Kr}3@^ zRze~JmFlAi1rsaELMx2l{gOn-HU&*VfR|d|CPHq`+6$#qq=;ST)`8mZO1P3`e?{m6 zt;SZ;S&JfsyIps^03q?aZH2+} z83NB6Cwl@9H-ajL(SJVZJ3?#W=%)kOXhXOEG~bId!_&RsrMd;*C=!c}xk}BRCOBQ% zU<-cy|3L~cYhH+`=eDP{UY?%Oiw<0y97K7uteH`T_@z9}zi`FYgV;3x;ROdD@$aWB zJOJkuxtVjl%&BMdKQc?ii`(h1jY{%!N7C1ezMBj1>t3CZ-3bJmdijJ_L`d8klJoFi`iq>) z`_bpo>{C(F{PH_(Kp@h7s(8`&S)aegolkJYo20J`)yM)G-O*J+v1|bxMSa5B@qwy| z*NJ`8A#+6HZ%}#{kx=7R|xwa!Ovt znto_^Z<>p#tXmiAhb*5Hx%J_VzN(L%mn$8;drTy-iY@BKnPuTN%jn}m!gT~ZQRJRW&GPJcyU5q+{%IEGR_QQkyHBcZNLBZ4H5-gk?# z58YuFc8{-~*HAQ$giy9R$Y&i1))$P`W&g2PWl-Akr~<7|3f*GW3>JRrAV%w!L^o`~ z=1%>~>F+`uZpjvu*4)h39XBWxFRr&Pt&olUv~?k}(n&e`6X_3^55E7!AXBs3S?{<%ZHwE{gl&FG1 zo81^UvSBSYH**9;39rO~uX6A&x*c33h}H?zj;s3CmE$)q?+crX4klMYfomp(Cg(dx zCXD^-C_i*(9#qJ(23Ex@xoGUqkz8E&eTZCOA!1DqyB9_2FcyY3*rmLvk*p_GHRC)` zLEH}qGK|D(@p^mkEV(DbD-Y{LZP^O)g{{(!Vpsgl0}EBbQ)Ia4WEE1*V*ag~F!N|{ zV!@K$A*TiFRTw9UVn5!O{siUq{8P{{rcO+cL339PSCw(=U8CmkSd~>@x}q#XR%27R z$HTbGd7R(+r*J&?_{*F(%U*ytx?r$!2tkQ}@3cqR*oQVzhR6+F)n2Z5!@~t@J^(FD zr6iAplL#{UVO)5)KQ(pyqs^r3UvnO;w5XWKmGw_+gF95YZoKyN6ioaicJqcw&}>4Y zVTMAHe2vgu`DuA!nqisVJCo-r*gG8N7glwnNy@DEbFY zb>4wKSEI0fJ}e_`%G4Pik`1NLkU+@_;(-> z85b6d|Z7cFD3Db}tUGm~3cth`%cyd{69iu*hKdl@zz<`ffNLrZ}<9^vYX zkbYC7kF|aP*xeQp3Q68_+CY9Pnk2L<3ga|^q!~g8ztCTYMiWj&yQUT^wY7 zp-FZpr8>$Ky2RR+cWZeXZK!U55+D5u^+P$#cLk!L35|J|bVKH|X6j9|qsfi0PS|vV zyvT34nFZ~r8d6C% zt;}})?J-o>G6lROWkVYDmM2iA=)?-NyvVEH>h%812}{NK7%+t_x24qx4&-1aGSG4; zsm9D(hQYX22tX_ooiLdMyaIf;tzuIgVL-q!@`!SW`hT=Yk@F8XN_i$h5lpMZTM`pd zUwLq1|7umfb)?5NUTT?+d`@N~38&7R+voCq(&GV+el;pYLWjn1w0J#9eAFK3O8SQ8 z>G~ImQDVhzo(vqqforjN04VJHn^!`17BJ5v44n%rGx5RHBT}l=KDF~x7353rqiUHO$q zA9!UMyaO)5EIY#N#lg-@tjJ}zYy>A3VfvQ0^EtQDj?4<3E&EQb(X|9uO@bFm{<3{Elw~XjpWF^fEks{S% zhRJF$a~HD%NVcoYMnDMhF3NOq56Vn`<65y%wKXd>xSEXzWShdDrb)tzA{XTKZ1ZGm zV!~FZf~6m2M!U^1lOiIr^&Rm$0^#3MUI<$Cm=t_M>AoHxFDnGeP13VZGUhlWuSHQZ zB%z|COU@ee(-h=`jRo?>4nZ1u63Wk2rx%gdMVy#93-Kz_3wGQX{wD4mkVv*)vYWYU z{hvJkIWw<{mSOzAE?VmHY1klM(?aKZ#3kJr#ME(K%xj(fB3qv7`$Iux1HGvY#Zc9> zNl%Pvv4@Q_T;ID!;TRK?#t0H)?1hIUAoS&bpuSJd2x0Y0Uz!*EE0mM5m@p&@iC;T; z!EnYJ{AHRZ-SbXkgPOHXC8#azvQ4^1B?t%p=?(fSF1;NrWfYY)F54|gvVtqEg-n0j zH{eLs&^G3Hso!y#9sya~+5(0w*1#Tj_a#@NXci}g*)5Qk0BU6B&0QYjqH>xB!Pfe+0C}#KJ(GfC#*h# zG&-gVJR}Udohtphd6=8F$zo@~qGKKC#xBcLZt$b=h2(tn&W-CTPiKdoaGLeDyDqYY zkuqp-6HGb=)iW9YL=>2JV0q}XzHq+j(TyM`!0Xx6N?@(idln;<*?BfYQ6aSVCPcQs zFiyz*BnQUK`xwXov)6M{s0yM&l$6a4wu{M7-Qa<0TLCeGfOa4j3tmFI3tCN&g)=bd zgMlaFU7uT%Z68eZ`qcDEj}^m_1d+RTN)T~G0_ z#iGejnU}u=CSo497>k~4S@dR_MQ+`HR^ISb$MQ1Y^P|jd)+`+DSoR!=U0g3&o;{&k zP>`ed>z&3-RLLfSmYM?;+FP^kLCsxgggCP)Q<}$v z-rP}}h`8_iFUspI7~4nuBof}uz88}=~J*;ZrDQ(t~po;(<@5m9-H&?f1c0xA6hl_2#pMX7mXNLg5*!; zZUX6VVAPqonvuqZ-&051n@?bY9DdA4Q=hND7K5%M8?T~xz3vHwaOs{j9x2rCD(xl^ zfg69Xef&L3`O`p=q@qU7@<{&MRjHJ9>ceD$Nyxp0W;XgF-54MDJD~S2@>MqV?a5|j z)0Xie2E63~0ktn*PuPEGXTKZeRw)Jst16$WpyR~EWltKLiFg5rcX34z%-cD()C)pR zS_H|1_NUo^3!faGLTYbIh=>ZT(_HA?tNTG^LUO`J7m;pQJE+)^*R~vlz-c}oFPL>( zXaWgP_1*|ZEkQLSXZ@eQ^yer=<`J>Vht1pnah(AKRp93$McLs40z!|8uDvo!ocq~{ zG1oq7p6n0XQ#{!Q;;Af&er{ln&BZ+%QF+hGiD%fpQZCyFxUPSoz%8rxK>bhfOkAyl zDYuGYwN=`yiO;&FZQ(#>{A2WxS}tD%Jv5K4YmJVoK-{AR`g5q+)L+#{Pax^SHu-SS z+H;=V4-Xc4_t%Lr8oZtXlsK2YF!}8Gh-UogHnJghH$2k3Buk(28oX1T(Mq2+gv8!= zgD2LHM6DjqR@t#ey~B59F8i z%!GlzKc+u5Dj2|1GbKz(8uUBrrcHXDmWsWQ$#p4=?NJ%_9hF{-E}Lo#Wm}TcpKJ8@ zgLT*nqaP+JDL(yqFCG+B`}2r;{VA;yFuZ}uai|N-hgg--%zE!E({|#p7qc1+Wn`qPa-f@ijGhC|!n_UOR}vFws8xuxUN=}sT6aIJhX z-MpaS&m&oV{=~@pQX~|qdCNUHcD`wm0{o7IGeRX%X@BsdiTiC^ox!(a({01?niXSl z13HES8(7I^Vl-De-KIA>)Xav~WA(%28cw?GBkR9LZZL>AaDkbJcg6_N^3FV2lkykr z0eIUF-tMrVFfn4$rjVA2k1jc{-3n+U;hDXR#_#9%#NsklfPR2&5p;C)=0nQ7aP|wc zFO@nMDUqCAZbt*(Oy5mO$vHE{x#$6{wUYOZd{Ri;r=s)FIYjK;In4mkuv$BM) z&~7o1Lp-y_eQ^c@5D|&cHLMfQ77;#Oqh$|21gE*)>;qdZf5`0rGKuflVQlZPaB$>v zPhY2F7BTLpGWAYd2EAOKXlBvpyL`FxP;jyKpO_D~y{(o+g|+cd{pISDtrcZJ5`41> zdin0Iwc5UmVYq|6#9~`qg}di>Y}VU+Zdl6zcmrK?+CaxkpftagWr~0aX)BtnU-u^) z1hKO4AQT;@1sb)5O4Fvlo3>n(>zF0nM^!x7Tn*ULxyQi)yagx;jy^^Q`-qB61dkZE zbVq%s<7pc0@ocL$>b@JI*i1#HZn_WM!lKsjfhP_UC{gAEv*DI4dfq}67G>zhXX7BQ zM7>RJ@`Mf`5iJ|ZiOJ%uwof5>T2Ns}odfHrTuq4+_5*^P)ntg=&(kHT?LB1KF_98q7dg`PViW9uhm@cZgJr&rDRo`-^HgOq8=1EXCe)nZHOec}4a! z&a`zuGj?8y)&}Ecr}T~C&34K`2?@rq5q5~Lt?Rp7cY)hD=z7<_cl<{RNcx`df&pla zpW+W$(Rhh(_dUHFbm}6M2_g52_|4vk+Dwa(vj#reI<5Ec)@6Oui0bHltijZZ0}FL; zxSn#>76tx#kO9x`ACL(cG@s3^;oKoH_<8JFY z1HDK2@piBH%4p-@EAvE|uOAi{DssccC*XpKqWUxtE6dfA(#o$&4R?n?;{E(%qol16 z%6T#UXQ4u%%{Sw4(WQalZlvfF$}xxfi{g+~+?P z_1;&Rh2MM=iT4v$@pG&s<5foVs2VFkR6fXV!aA5m-IJml*m*QW;KGxNqC75Ynw*V8h?-IT7BrlAN1om43AA zY(}nR{;7n8#PUT!Dv_1<-8vC}biO#0r*{l{fI(SGc+FL{Gxnv4K!xF?KnkBlzG~{H z%eOSP5W}#3yNsDAt_>3r$TOx6uWlwh=UJnN2)oOCA;sz~G_;#eYWS*7_{R|Mz;DKd zT;`4T^Dtu<#kaB(p&?6~yvq830I zHo|*gAC|&?L6&qZo9?2K2kPTm`XEc1H-Wk%%2| zQ_9_PJO>c=ResKvK8=;Y(}$s1c8y}!>etR9fBGu1uOvQr|Ah+YEqZ4$paUEEr#^WY%pJ)y zE{BPb{>VB!jT(rkSyx=Se{Gu2oNNs-xK%iSJJ^WRulCU@)n$=(OI>A@-bnGQr=#dY z#L-|_x*^M4Os+!lp`gC!Nyv_^r0IU^)@|xS!L&;A9cCFg+aNU`bCzDDTBn@QkZRju zY5}L!B{^0;uCNV4T@v(z(P8#UPtp@w$swL;-XEBcNV<~x3)S}}R(B^mE2UIYN1@o0 z^NeBG?U$i;alwwPhw?Pt`1=5@@hK+#W6JI*3iBt)gwIK2+~!ypTY z^#%NT^5Bf-K}BC4F0d`d@x;FCC>hJ3IY_D~Z?a7HNe%Il?8#f+bdM>MoOsQ*4Shn! zrfTq0TAIPwlMg^Zf;)FRS}8SwpNc_KkWroRQp6oA3kW^qhCs z*wEY4+aotw!d)^ivw{_X|Ax3temNkPEB^XiN4R3&5myhn2q|cPF zBH?q8!_Nl?6P$|vYdVp z-tT1cX+3_gtVvZMT~j_)icjdd(`??IOwE5_@K(rlCj^@ALbWYCF59KaTX>{C?cEdx zs@gu$cu?O!r8kRu?)w)We!f5HrYJmS*}D{ap@7Xd)6-G7c&;INr@^f<l)oP+#z9n>9(eLJ$`q0vKWSx}XW~ckf8(p7# zOR-z@TqbHEv(-vX7VdTVj!^g4Uc#DJ1i+@hp6T-rf^F0M5vxqNWkDKFb8iqQ_MZZ0 zH8QJLMKXS(fRgvJ4qJ8D3pr|MjUX0@CW*D|kM2(g?3-FSKQI`LTgU7N+%;x*a{?iF zhGi&S!|-Ooa{K0l|B7=cB|b^5O;lwm$kGBmcp@8uC*HDZ&PL>OY7Db*gb}8^F`538 z4=gJ5SK36CHGN&DF842qgwbI_DHrcHkaB>u51 z=y(hK5aBI`EV)Hyu0r(7*hu5ab6{eMtyM02w$OpV9b<#K6fJFcIE$#K$WT7od~g6k z1c``~`(;G;cI7E#(7141g9>Ij4F<130GWHxLd|!G@9XZ}X~owfutQyk&9d0zwfRxM zEi_orC#Tb#&ksdqF8801)kdOL2@xmz=*;)CmT{iQ$-h_5JC~VU*X59pZ=dxdOo6*e zsOQz}2~Pn6xhKH-j{qu>w+^AChA~WE)}#fPmww`_OVrth+z728# zV8MV7XSGdf$wv$FB*f)xsAY$io0l@nnzUrpMu<**;%WWJ5T5bv82M`wLGu z$dWFfJH-=OHV`Zc&$$J-7R?$+5oLk8=Crs5p`da2a*T&fWv=ytx@1A>4zfUL`VA#x z^x%vy-#nI6psJR>2bsILD^4m5+t4@h2D?&OIi2L4;EY7waM2!J#?rCFc+l$y^y5P* z7Wz;1pXSOSW2Y@9CmIFt@ln1Zq0yv-!*Pm3oZ$dS%deg=`UQ^zU zouJwnKGB#qpWb(5EzLl67&5x?b+>mXels_!|3aGvwFsH!R0*3>|9c^2=By2lGJk%g zWL|Q-PkJosxagw(5jjS6JS;A!LZEI$mD+8{>LFvE?R|1v;hREgv!V=*()yuEibp)|;EN7QP7G7^+&3}s(XM!Q z=Ht&|qp#WLSj6}tNR#!X>{EbRt~ANnd0zlh#e`eU9d}^Ph|gk(AzkjXD3e7p9P`Y@ z-R1{x_tS9vWK=Je1v3^L_vp~^Dx67N;;3ZhzKYE574W@wT3dBQSv2L{N)3i=HdBEG z5mZ5TO4SIjtG%^Omz3`S%D|6Uf9@!);Gv))=4s_XrGX7|38~n*jMox(@5>+Z(F0xo z2J7!yyspY{FhR6RujqEz+j}W}%W)0g#XgI6{ive%#qp!|IYyEjqR1w=2uLDKF`hJo zHAhM^v}DDmReWF8@>?5L3I7_vqErGn$5_O0-S>w6)+uu zXL>KCy-^;pigIL^b{$LhrEj@;v9%D|Y7n%|)TrayIdr!hta{T^l}t!KVt?%;`?9l0 z7}OA5g6P+yZk-G;sVrQ|agrv`%L$dg$D+Qyb_!Urc@fIc1Kizv(yU-W&pq){kR0T# zq5Nd_)789B@9TnQE~R1Et9Zn z9cQ7S+BxOq^O(C@)bgCFisD}hb||rL>2%>Kb?*+M_u-(-a!lnUbE1e+AmshvErqNrS*s@clfo z?2bfh#1b6jxHUv`#k+5)omGaqXRP%$=e5cbUs$Qgq@WXxztq8YoxANrv9-|+KIm_1OU=$hXeQDj@00~KO z*RA{0D}@X{fFJT^bpEW#y0)fp?l^D7Ku=#%DyQ3;&xt@u|e`rAGzDSJZ8K1SS$5-ZWn7(S+xJ&Y4wKLFkIz<1*j5!Nm)SLk^=_H6tW1ht!MIV5<#eI?k&4Z;_CT9Jex` zp6l)8t~YBFQTRVW*J4+gZDGXWCTguQW}X`ms2a7I`Ruqca&l!_<^GR-FIIc_$z)DYEQX zZ@coeuPTwwd-C&Wy-;k#cXug>V}3uU$Zkdz$@77$fxGZqJWFd!4>Xq|Yes*R z<5X~=$R0gM06Xfq}oNef1&pt)PHNzf$X0gwlD@<634~=%X^gv0CS!lrbC>}Rb~#| zUqU{3r7>{ANY<#0t9c_Ut(SN2dz}|FmnV6pe{m+lOXM~-Grh5(PdfENx>4rEN{verYPj-kt?#G<-tNqEqNjsgXB1jQu zUKHnXX@fu|LwM~L3nKunJ|#v5&v^9PAIqxA!L6ard>{dr{MGH(CCC?#Gky4!tyJh*CI7aRI^^ za~eEU;HMfR*dZ3mwDo|P@>H~xm1r@$vq*dtYGjWY} z_=jgrOOUNNJ*{%d4b2_Mz;D*jHPh$?6Ueen-U`k0si!9#I>^zLOcNke|f2!Wnz{P!8riH#f=>ClvSx@gyDCGOSqygPiT)c#cJmO_ z-fA8^@qNR=UhEyyy->o(USXQ6-dCGO%vu};LV{ljf6C+u?p1~+>*(5>p!bshB+9I2 zs^<7+9?BOFkrL_k8FY{_wI9J`dn8-z+rpX1*`cg8`2fEJ0lr^`uFL-q0zv)0*C(*A!e5R41CPT#CBD!v zG#81kuA??kO&R19%8*WQK;zi^it#bIV}>8vbw}+yEyjz8~vvz-c6OYlujdT54txoIrb*J1L7xw4}&$U9Ua^4(N7{PTg3P# zKKMNU053}T+Vs7%-1lQz6tO(AZ<(BygRbb7mRBU(JeP%;)_D}G2*~+YX&DEGCqJeu z(;%?5xbX7oVoxe~?EJ=HLaQzgbB_Hu_pdDRW#*4~_O_lKv{${9#+MMgk1=+fF~|cX zC?}xgel@Wkq--Fw($@a=;#j2uD|OSGX^ncckCLiRKngRSeL3WGC86lTs+1Qmy8O?e zz8W^OXJHlYN=Gy<&m-YVfzz9LPEw!zbH&S_# zGqjPw&T?@0-L!L$Z*yF=FwP5m9duoK^K$oWeNpho#PR8xbd9dsB3sXJzC@~r%vCw) zGmcMF+Z}y=-0>CXgDt!xqF(9uHuqY!&7fJJj!_$1wn5zLRPI(>;{+V_>Cfk`h2lFs zUe8O?BZ6rswU2bN8%7Hz)6Y1@dCmtu)%0D)sia)mcxyHZ&W{2%?P?7S;sd*OX&PnTZNAy$q#Ae^t+!5spHIbON(XmbXx8>jtB5dvzS` z8$wZI+aA>?{g$I%LRB(SSOUU!Wfiz87iUH~4inxBmbMHva$-$c1(L z2(SFcj^RhmhTDc#BOv6T*1a4?d79>pQL~g2ZACQ`<1jf+28BLq(&TQ}cDwt}UGOx1 z7}x$DYK39E8tt)@X}I#(vxe)G1Fv8I09GrU@H`j4ZqyXo#W&dFbM~u<1i@dRB?!S8 zARe8)YohoWZ#IKxd8bFES>0M#vw8P6tX@ln40F5^S9UTu^y!jwz-#^{)}!%Oq}nBr z{>>K>2e*uns!8B}9{&L2U3g5d0UW*?w`50qeJbj+ zW;(%7Mw;8oKP+JK19Tb4>OE`2wQXlpmr~e> zEv0!R-z3Ud1DubP9!GvEVXIzR%V#~bY_rJTT<#(uZSHf9gdB11E9GnEn5+(CDwtVv z+4RusrNCLp1|;NUfZKKQ6WV zO&YYZ5mKkBK3<})P4Y?EqvQLHGU_>Qq5*}wZd07G-RaM4R$#S+MI>;$qeltdDr1F1 zk^wwtjC$A7o+a>)+9P8OVcf~NvP$p|Jw3nAHN;%_WIZwTz(qYl~}rvNQk<<&Pmr>&MVkSGG$UTVOGRY-S|frB*OVApZb# z`ySXm^IpqgqD6lMaa-ELE@WO7D4CUy*Pe25k7Ms%eXZ#CmUlBnIoQH8=B$K;Tp!`} z81G#Xsm~pcJ-9lKJx*~&yek_Pn&Gy5>E(c`x#*`SuN>l{n%swoT>k*0#UKJP1RI&8$j(n(VD{D?=aY((blfAFDB~RFZL*B*Z?8Oa{!K*DLnX*& zbNin&?23%aq+_8S7-Kzq^Hn!2fV^vL`?9f{bP=k7!CVe9F@x?6ZAwzHvV(E3`2-Nm z>pWA$(poO{1V6*Cj|Resa)PQp%Xqfm03)tMM%KT z!WEmh>%~~Mj?zWGkU?*4gkLy93YiGwC${c`BhXXrqCaVw9!TUX04gP8lE=BmI(7Qf zQNpB#NJPZQcFc{zf8qr7IP^80Wuei{8jE1MK{`Pzv0pYX-73g-s)BgOKyrVVwLPxT z%)8_V0ag6B`A7%Tr#yq}L&X3MB#||+mpdGg!=^d|pGv76tU!|LV*)T!@C! zME5t)$Qm1UP`EqyrqR3D=hC#$fdpb41&u#>5K*1o$8P-d{c9>)dsq@k+8vUxUm*j0 ztH}EF8NmMl3eg)k$|A}nGMtx)sgg`}=kE+-pIrJ>+{&d$#SCl2iR6wbwmchrp*GS9 z_wDbGO0Xv-VstU6hj+@n1}CBXD<904GCai;NOvrPGFe-Yd*dBAsZGivJb!sYWlr3R znaxD;@i@rB;#|!fXV010z?C;d6t`bto;~}16`QME#<9t71+|U6wZT?<>Ex0|Q;<$a zKr_xpPXiUtol-+|ZRVO)lgws`W0P*=BN#a3jAyT}wL^6?-P?ImFO&%?cCO+%$6E4h zV%^#En7qm^o3#&IIe10<=xt^pkv4d^Y zd$%d&7!bjF7-=XL8 zpcS=8c@EIZ3`-dsOr5yz#(g^GyXe<&M->{}(&o9RYjx$9Nn;{eqGIosR#nFsJ+cp9 zrYoh>ZkksO76^zBG>{Y#kJSGFpIYHBUh43~_Uh5Bl5KS;2_A&?y;dsJ~Mlvbx`wL(lsR$wit_~M|HTvZtiXO%o!PD z1zI*3+r}_S9l_*}dgt$Ch8ba!>gw*`5JxJhkrV}x zfszJBJ+u95I&o;1>}ImNy0w-?^X0X;SY(ZQ@WdVuuqP+eHL}*B?O}o`KhZ7ZW}ZGl zW<79m?NR-rGF8BkrwfCrPv&$y)L6nN6T%XX673x#PGd^Y6{d#U6f zemnctvPiQur}w~#!mvwXLXN?Eu<4WPPo-0{nr630{m>}@SC1i;U!F%oK>q*?_2+Wl zNxsk$Io%_M**vA;RLR`>=lp1ll#!>_d0;vSV|9_|StW)tcce1;aup}8dXG%hOBCWc zgpz*scF4A*kC{)WexAK>Yfj!*iaV#cx;Iy6E#*q#rhfT7J^A|9b=}e#ltnJ}TZi*l z;aOCSbKf4-)k#G&#jjDhy-Lz=L@pfM7uw$_;|H!!sOeZ5oQk<7U?qZDXF{c@9^Yy9rpR*Q*38UP9(j{d$ME3sgBy-lZZLBS$b2Ao>QyJO| z5(xZ#dVW6D!8G}es8v&XnQ>TJq{%#hGx;C8jjozLSP%(SBX&CA@x@%80}JxTMK+P` zJPoW#$ovP>uUffxJ*0591NmNHP^%GU?axeOp1rVhR1!I5b=VwQvk(h5?W6j4=~C#q z9-QY*M{}UDwT%=(AI^4pkjb>}+&_f&=RFUlXzwtHptiV{Ia`TggN8Zme!0b0o=@Dy zEbeXo(y*$%vZ+>HdXwmT4{E}hFXxIxmf;oi^E7dlW#`u?u*QD1!75Tm6mj#uhf-v- z4dxikPTN$F#fu*2@&5omwAtjjxGNknK4XxvAx_pDjCajfv(p}VqcglwD(=fia2*)u zAA2Nw^Iccj>@A^|2)@zg2*=r7ZbK-O_=&*zl=Fd}GC4TqLCsFbuZG4-D(vMx#S|8> zO*E3mk;vJPkC&2g3F-d;*QZZxmlJ=Y1Ov$%QfJ&l9FvpOW`7au=c#v=;{{Up3*yw9`;o{iknl!{FNnSwPo;cBR@+e)c&Oqn3KU#Fg zF%t`ozGSesl%dGWcE&mp*YK?Qu3A(;o88(l(nbOM+z;2^AEjnJky~QJ z5oTr`vDc276|114ci?jeQb^HQ(707!GDiYJHj)_h=idXrIIEIaTtJ3ELYszH7Of}D z2Tq^otx>UgKXUKp0VxeDju@Zw$Kh6FjwQL0cwRy-KX%f*gsPw#+Ej^CgPml34AXP{yeyV%@hK9Db+traS;`myl3xl@x9S9_0T3ELCSWMZ?dq1P$fH zuoaXB{w8kf++))R)~vfob(EgdLF&I*G zMYo#ZnAzkJC|%2*nK{A1$KhEjoT|rdC}>to5_ZFDa*D{UzvSJ9>5>5%`Wi)@BWac< zl4wyCZhWT-O9O@g;QNpN097^#bJINu9Xs~-ruo6`Bn=#7N`KYNcv0`i=~6F~6owh% zD9o#Xp^BjApwGYg#bYOC3K36YBb%wfm^o%}1ThfXNarUfrg{OItQm=%yT0iqEhhd; zzdtee>-yE{JecQJfXyN+?uJQV5wwe(Wrj`)cmB(}D$SgJdM7C=WpfN_E{Nj)$K$3tu`(*MA^seLkMr+L!$gH- z37NrYq(|J!xyLyBry%fqV2-tMg_(TueMv-dE5sv#BAp#mY9fVlqXf1%B;aKC=RJ9u zr3kn3x!nF~0ytPI$0q}#j9{of{PpcsXP$WOV-4gMc)Yg6Kz!byju_*d_xGqIQS+=Z z1@rls?Etd@jGw?`^7N-B;)NNci*sIy8Z|^x79$yvvdqV?`Ny?V`%AI6GeaDcByIb^ zyRfH%3GP3_h~7w}oNWWlhYRbUtt9i4<(OjvMhd@YTmc&N{{ZV&5|g<+=@)T4oO?vr#-K&)d`^yHk6u4^`3 z%&EDE+cLa-ebBl5FnaS^mnBjt1;!$I8M0-1zo-ldiKHY072%xuJ!4}az(%y9L zxIla79Plxp!`M~#nQdojP0TK*YO})3BP;9k0CGN^y(v9SV^+_|q|wOJJhI42qI~Sc zee9mK43SE~qcemv05ZA4l6v~_Q^>eogt3LBA@Vk}9;(E9jyR|UQbQE7BofPUA}eA% z6@+x$#N#8NU#C73>s{@CKb+nvCAm#PZ$7` zjw#A&Mt;d4gavcvF_uPeo6MPtV?2@DJ^lXxT5 zz*Yexs5-r3?@yNc_UbbQ!-A#(yX^3+Y7`6uf&BWM`_l{` zxFQ#hc$*uHPr;M>pm!sj{VOWUOIx`jHjlpu%F%P?77flp9&OW!UOjNAv< zo?=^tdz@jI4_tBiQTB;Mr)I+vo>TzDp85X(1MfoHA2R{5`^r6&7>Mr}2ri76>$M2*Ypj9DzdY<^{{OZ)LGN+o+&vTNn2w@>) zBio<{o}#m5KW8rrG^-JCcTB{c+4RZBQ^#s>o!(NU$gwJ`4=u16!91Mz9R?_qy^Wnj zX|%TZSz(nvXxUm>ApxY3dv)qCGJUGNQb_3k0P*nHm*<4URxrM**ug(fe|oKNZ*x1W zZc`A4D$YjbC-^|>LB>r_1oE_z!!*(&22}&hDpfhi9>=feQmRPHok&%a%oh=0G=^2* zxw6gakMX8&iqpwhZH3%~NLdw##EcIa1#|1q8SPVDfRjlyaf3XJ!5i+z*y9}!KBlWl zr@-D#!-a}P21m8CnY@_Kr#zf{{{TvAqB&(bHeGoy8sa}X;mAhY4ZM=Gq$B&GdSjEv zsWkH53@si&luoi1eb2f-QP-Y6zMhqEnQrY#^IAz`xFEt1 z0>QD9yRRLGPESr~sb>(Rl%=l2uG#}@JYh(LMim+?ADEwRf61r>3nXoFH~Fh@k-G*P zRe;X#aqctCRd({l%dur!U8x{sBXf4Z@5fR&>)xbSbXbgkI1#LpNB5Kw*FTBrh79%(KZHcFt3G zkqeeZK7gJ`_dM}P?h%Q&Z{AM;Y(`EOJo;B`J_K|vP!n#G4c8YFKv?Y_R#+}@2ONRl zy;YJ}$XVR8JW`#3)D>m-6*D{x6vyTk^M=(p`IiSH*FEb#=_VT%(m8Hh4fd$Q0I}yh z@_85lemywNHqtV5;UrGa2#iS)M}H~2!Vr0i525RVI|_7=$0U%&IwUbpRlZ3bRaL!6 zJFqjKU#%)bXpyl<$!&$0Mu2XU807Ju-DhjzORiiKsk{O25*#z zLbiGq{vWBL_b{m1+hS&cA!*tK{{TjSu`t}u&mm?UklY=+xdWn%4%MG&9ktsH&mv20 zDx}D=6;Qa($~}F+{#7;u&Ld(A#-F}JCK*>J2l2=0O9T;@nd9>e`5BRvZf@t3*FN6$ zP`@!MtLjqBF^J#}KGM?2&VhzmN#l;bwI#opuF`K+`F8A;6_gTq#zE(|n`hMaANy7351c$ zGPizDC-JImW->E|P^7a&yABBa`tw%qEo=lzMAH&tI1zlxvL1krqXc#Ir9m7(#?B-P zp~PxNLY_8)2eCZ+`&RBLBe_|}VhOcBAjGW5w)oq*vGT4D0QNaQtxpum<;OgvNH-12 z5H437AIJXyuT7dI+?k7XCnRsj-W-0JsL~lNRioxXxUdHUZI+Na^0C%iZPZYZ=WV_0_fS z7MDO&_MhD$_OkhTaV_U|f22pPr>MMZL!qDTeQQamcTk~k*XWEnkrf$7NnD!f~e zN=(v9?>1O>RpS7Aas27PgL5RWJ4WYr`DNfDH(r@I$0nvRawbodhi=TYF*#|XUnVG! zu=5GvkOpu+4_?(Z*_>Uj^-nB7a}w=Rt<(|*4_@OHT6dNyV}&DPRD!uAb?NwHpUR|? zNT7c6(@^pu5$;HPSB_CF~&j9ZrJyz#6C=|b&v#cvH*-W#~J63 zO#N!j%FA|l8F>;G-N!#){=cnfq5?!{(kyvzJIw?hy?^~)wB?* z#~y1tGYtIL;|r2O=N%~{3z^Vg`NFJWTu3JTS6dqtHB=AHJ zl|DXY8TrUzw3Zz`col~;HBgEoon*R6E?7o9vC1@HDFe0!JqBs8MP{fjS9C05Wsce@ zHpU;&WD;-z1DdsKEwu1T(c4JVB;^+N?HMF7j<^8r!yFTg^aDH^i5e-9qK!g?knIEj z4mwIeaQS_^(1DVEzV!GYNM2}`>NPRMvNxC*tc37Ua0m=Do^S{U zo|QJsY>{}%BxK!hAKKM_b~E!fc?TeXz4-OTQ(0~f*-f3xLw6x*ui1k~8+FS9OB3`R z=)WsAt4`5wdKZi5LL(trf3x$eb5D zED7SobGFzP3s(|PC=0bRcV)Razyy>1GgFBojUCi3Rf34!@)!}zWPV_MDyAEI38L8l z0A*aVo*Q;@2Tbw&#Ue#y<{>r$##_o*)qu`AV<2P${cB0dqoR~yZHVq?nmM9m%9bWDGvx|S^8!+<-2GoIL~S|X9NyBQ438ZjUMqw|FTa=?yH zzI#=FIoo`xxtSypn2cpXWB7BAZ^o(5nWGs&qU?+zwh!fiBl7-HFd(rQ$l!OX(#0&2 zVc3HVyNf6|3!ID|hmPW$in9r#krC9!qAl!8D`zD75O}NicD_U~yI`3&gZAln%GMYPFMy~QZ4>i23yzp+(umCaqmEc-ELK)~qjanrCyp_=FgZCV zkVh2fILZdm-$E;kR+4eaW-PInAO_A3G8Y|(U#G2H7VQ#mSH;4riJC+z0PnZg<;OpV zYHhqz+HEpTE&KlObgqF(UYzX!1JfiAdYa|jq-Nm3X!5y@2$-_SdiTf8j>E9}){0Sz zM^qzp4L+W}Y&N$KCAQXEiEm&KkUsYukUD+feMhZ2>NSohw)0av7iin_4cX`1AM@6r zYm|)0@!G)&+Eg@dNt4`z$ZX_s#xdVC#g)aWGlW-6GrNK?0Ua_rb6Co?)roSkIx5ED zWtVXJC^890KoM6RjZ4+r$w|zSYV3< zOWP=rvB1vZ$pj9Er_|F{RfwXOB_dO~f}TZSHC9UHf3mTdPcW7_qsU0S!np001BS>a zgWQiww1ts?n9S0t@B1E!+uN-mU9m^brhT=#d9=sg#X~Hd`PIf6H z&ool*+@>}85U@LNe;yC@tKU43tdef?Jfb8*4g+?^dX9S429gMww+2v8mlTm)6vTtn zbYYC~$79;Ge%{3bysaQ_l|we>IIe`OWf?e#@p%dakuAi&U-~p)kR6EVI(*BVfOyLH z6;@_wt)x#cCUN`5h=3V~8=Kq?KMI~(o2G$LRyI_2^3LoXzW)7x$*7@_Np1?Pg5o&> z&A8=r!Qge{*QI9W(JJF*c`a39nHmR`hnK&C$jS=w*N}7W4OsaCd2xJ^#LMLZLnv%^ zAJVE^HL^zT{%Kf&$yFHokMRbcA|Zq<50fEA35*@XocdFP+~}oy7TIF}U^|tNWfWkt zcPHZ2;hmM$fLTGw;PZ-O!6PfgP)Rg$b&Hh^*aP1kGAYc00;1)Z z`Ju71Jhn5AeL4MWR^e+EMLuoHaLB+q7?caEfVT1iK_hN?&MW4{;!J#r~!5r`d8Boh$Kz)En$_8IApdYp9htS=j# zak?|2u}Fj$R;}gAW7^19Ca)-oD7>_ghjxR zGsu4M$3ISZ{Hfy-3e#~T^c3>r*K6Go4OOWx+E@?y-L5Hf{<0C5h?ZrBt(t8LkTm(+#?N@4~OV@;y~ZRw9{uMd#0h*i;K9LE_r40@6IWd0SLY?+(A%Q0Rg zu$lanbdg)j-JJC!JP<(#)|;7_3xpB5LxB^q8@;%ymvW??WeaSvmXch6s-v9xV~(b+ zLPQp`d1czz5hR;SI3)3t*QV@e-nwHhVP5Q6B)5X+&9u*#F<-PIuqv!FGtP1WIOeI{ zL|iB}p}N{=M+FfqX#p1kqWw2_ob^SUA1Zo6d) z-y~pT7#}FfBP5KR3Z)KV$}Zaw?v7aEg_(&X_koEFMn63BnwZTCM=VOa<3OpgFi7M2 zRT$!9dF8W=qHdK(JhwyiKj*z9Ol>Ztlgwz9iz+zaVCO!$6iVrw=}9}276{S>EJT3y zUQZP&2_cOP6Uez`WM_+l!;+X`&m0~*@#|5QFqqP7+jUBl+zDxp$Z+}Sl@B#KLmZ}fMxc&#Q1^CN9(q~zzzI6QI*0|SnP@+nhr7{!EO zGOPEA9{sw1DshSxx`JW$cAXi7ae=mFjq$sjeb&Y?>b%kRm0MS6U96#&W>m9<2~)I? zxgMX(nr^k8#Z-mkb+D^)rurx(h?QkB9C7}5{&dG9?bDV;j5rN$isx_~=XQAZ1KU4I zB%RXX3~epG7B)$&(By5Mx zN8W%9tspGfC!G6dwONp~%@hd^>0VMIh7e9b=zku=-kTiAJjB8YW6tEd-L$tjBmxP? zwL{gdN#%^&D9a>QmoO{Cwo7QnrG1U6jVcTy$$)PF(02^RcWIX4Z zw+yWWmnCPGRS|%&+#+zi;PLBR^(W0Dy_16}-ADF$Jj+ND7$uMWRCzm3VaX?hj=a>? z=IBha?nj;|c_t9bs!n+a--?lZxvi4ePpA1Z%w%aTY{EN9{6VC~=EeZQ;9%peMj?e6 zrD;(mZelD+9C66*J*a|_E=?LTwY-*dtkK3UWMSpqqmd+ia;gCU1Jv+-=*Bs!5KarM zmkB8$oJYKH0OPkDjzB-stB)(oHu6SCmdzqGautp<>F&7b54Bjiw=>zu@XTXrRN+V^ zLB<0foR4Zv$w3_Yiv6Ahk~rGk z3O|%pS3kppf(Z8==^yNc+9V&nmmfAp-)s-BdV9-;X%r%slnBtV+7G9HdZ_TMvP72~ z1kuLcSVuVvobl~R)w&0JlBzODk+NsWEU>aj8*-7!K8JTHWEo_=1R;Zoh0w?vV}B+Vp4aEd~#%k}CHVUOokwoIlcwOH99E#@@KyLUM0 z+n#cLY0yOPXC~!j@|$x$;u%!uJoO&mUMon=TXN%Ow=9duV%_$8D={!avT6uePO8J0 zzGKSggYG(zY8#kL(Up!zNh4_fK)ZHELH>Ozq;C`43zT^RAu0m`c{$*B>&+x$>6$?u z+B-=ikh@9weGO}|Ei_(u<4bmE(OVB5=Z!GT-N`>r^#!fKnj879yoi$7LdeLXJSQhU zrx@kEdiAS{!VE^LBS(z+aYP0QaMw#Y)bUNiG{83T`RYHBV< zYDI~rM&Ar@2ZA)ok8b8>BZJRu_x}JIjU|)HS>l0w*nthWWtjB9KEGZmX1&C)Tum93 z*LrNhD6@DP@RD zBZhFwUQB1`ew8AGhIJq`Ge~l=6Z37!893~H=^M@{>{HBWq}=Qx18R~wwlnE~Pvx36 zMRPg4GR-oTK4OFlVdJ9nmRr>(*Zi50(vtf4`#BH^+&}VlYNdp}{YJ*-%^P&~O30xzh2Wll`qk2<6JKJZ zYY(`Emfeb@+zBKed{McKuqPiWJqXFctBj%u)-fU~0?L-`S)XtBna|e)=zXgyI8Dcs zZ9LK<{pTTq$it}s_9xb+F&Ots?B9L70CWx%vh$8V4waRAXiU;$<9R%SlTAImiy7Ml2&}WNbMu@Mq;wl` z!K<@e+B9m@TBK~ztHToHWrqZ?_Z^S5Mdn8(+)XeHqd*I`xU0H3`)+LHLV}bG@ zd05C~kwD#pf!yaEfgO6&A%lLwBF008K2v0=Z17LNr_fg{r6fe8k`fpcs!JTHFbn>Z z2u3mi>yW?zbJXXjYSvrW?ZO!@OhaxFB7vER&+#5W><-?;`!Xs!mDBQAl z{5S{m^`^-bdqu*z5;rRwlA%fGKbLA`PP4}U0Ad4jpWd$1nAfpk+b4{B)y2x(tIHF* zx`YS-3a1}<_x!zmGH6$4O*>f4Nt!vNo!vu83wg->NzWMn03WSe`z6HIQd~3=!!QI} z#K5Zl9f%-<$Ec+?%O{$$sBPnF$^GwK)T!ks?p6N)bYB8B%K&kV4)v;Xid~Cxie+CZ z?NmJ8RM3dZvl7a&=cvyZ!8!WH};;uq&V)GY% zM20{*m0wX-BS_&MdkA58qXWu_{HNG)`14yiu46}L_ZbnoMTr_XV~#zg)sT6OCq_9Q zpaKEu_|l}(G|cO2vM0^5X;YP49)$2S{(98&v^&d;M*dQ^{G0{vpU$KEV45Ng!^j!` z0Ci*oe1URv>CSlX!S$si)wCi|ZX;&OO$$dXf;kbL#OeT6>9h{xzdpXz6gLs#P43Mz zyDrH1`AESS^gf>T5+E$DQh5$|igi1Oao3C=O0LAHbo)B}pa$NqmU)y5F=;{jvG14XP!S4n#eXTE#^GRr(}|rVeOv1N#eIglqxp2HQ_M% z(I?sN;b_QQJEwjTojmo!@()n@~?7)tjx{kHYH))$%LqknBmZ-!mfsh$NB0RA^ z=AXr=Q>V;lrvvh$36c&NOGmT7LC%tAF& z3c20exW+#Z@vDx~Pb{+CO2XbCzDSN$jF3L|8=kr8j_201?<9>Zpoll`uH}5b;Guxz z40?gd{zA69F-lzekgV3y#J^{eiJm5Q1y}%i@Yi7xIVl_9%Jc+nx< zAKF#Gl4G3X1fGK#z`z*KCpAVBJRV^(`LJx_C1A*`Pve8yk)F#tikMzFS|mf%CcyN882awTSF`PB6gA`Ry$+> z551lN$sj4u1CMLoWQh}8#w0RFA^8>fKE!v(&tF=KRb;znl1bu>%Ns}-k1k0EL-iRv zpHo+S#PeiFO^YI#gGb0J4nJRd=66izoMhg@J=MsA$#Clw&4`jN3buG9MtH}kN~0vq z`h*L+myx513l%JJ+uwuJ(xZXz9EMdgGO@tiS89LyjY=Jo2yUgw-y1O!DOQC+KD_(> zKJ_<}=xqqJC{rBs7X=V*E&_rWf_mq!f6q!GkwV1w$@X+s3K3PAbI^Rf$2BBo$;?3N z7nd>53hsHJNcUvq@-y>s*BIy8nH)C|p-t*GNLJnCKPz>|8T@#n?V37vdY0bk+FOT6 zo#t0yT!6uO^fjEb8H`0>*vS^ty9*vpe;kg!ohrgymqQHxN1G(XTo~ahtiHUH&M-5c z)k@i9H;j*Rim?)5kT2dndCBB`J?pwJL3_NVi{Z6W*s%rT1AZ77)DFado;|77ixWIh zwq|If<;#t`Pq+2=sqZ6+mTxamOXAUP^WbIzOq?=cyTgbl*+o!P>Wa0di+B=L%) zJ(@((t+k{`ZuZG>Dn8P(bS%RMcLN`Qs~}5YMa-*~#>;aR(2!t`g$La`v-o4yt>}qp zlJ+zY8?CYhRmH;ZX2TwYpHc0{0;QGrqR8Px!wP}(ZCnmI4*Y&JuroB~;^CAjwmahh zH_h7v^5@>0Iz*P!O2RaO)r&~XRPN6M9Whx-QJh4iu1gxMkVz{|<;an*GdWdmcvTy5 zy9J3pgW9Vm@LED+VEAauCglyBbnnGa1+~bwA8Jzsa>Ke+nM#(7jH?d#Bap+WK9tyo zqim`cIb)Ev*yLk^V_}Es*r`8UC7`%sS<`SYb5;0u1 z2_IetYdKW2u_~iN+$NziD@!D^Ob#SBG6rc6spJEisgWBPjACSlLP?22s2Irrk;wl5 z>($9xzjbAitsA6jv#%*u^P zT+r0xhS*M)?GKZ22y19z2W(@m(cg}o{%5UHuxKrj?l;=`GmuP6bRKBS9AL&W$_@`E zn)dRQGmA-~L;nCT5<);`$4vWi`c)$YvUw!Hw&g+ET^D&=;F80!;DCL44r<-a;iA=> zG0(Q*SYwp3v})gH$tt6uC3yh*`+HS;xY{VzIW6RhX=H85Dg@jBBrxZYM^CLyCCX*3 z*b=mtqR?bkFmjHcQ|D23p8 zt-_??M$sgDzGM7EaB4+csV)oo9%z8C3cHjjImz@PusErFfX$gCx3Ousc_t4c$Bvl* zjx*`aLdNbr%QWpYGk>UIGP5dYfWapEVhMBQUD!ZgoI^^Jn2Y^Y(C)$$mTP3tM(%t!n;fBR%#^#f0B>>|* z3?HHNr(8;|H{s)0ys%ua%F&Lbp56ZdI=l9GBDsk}<9d9iX#Q1FM<9+t`g_+Lt;}Ik z4KqEG+$7L>Yi9wsA7_drD;z86GuRHstJ~Ww6T-e+QKY+GS*{qz8!sO-92^XH$3Q(Q zX=G%YW@9R}%D_JcFuj0N&*Pp!9+X0@1=_k#8XuLFTWrXsN2dS{LGr#JjQ0HNq6$XX zdUD)-#}fx#uPVW|RJ4>y9)H_WR z;+`Ysm?vN+NYJqJ0}u`eJbL!Y&q`SxW4Vzcc`y}JM~n=C*#7`utw^^-$Cg0yF7=U? zLZMXk{{SP>pp2}gC&ESo6D+c03y*)xpRHr<5ryS)%psO3e$f=u?SeS&514mt1fA!% zB;zUvYI%xX<{NdMSGaGLBP9I4tt2-q1coq%>v9z`fLJj-4_?{n?NM9U zX>Ow6FU;M5&g_BT8274Eb9ODaV!X|mBZ@df#D!Mml2%Sh#sMGaij5?=1`BAJ7>SEq ziQ)4kj4>fkP*m<21pO-Q#Ozg~^TfL%+YDieVB3l7`2PT$(`;wIyhf7kVUAHdY=Srx z5hET8FdLizINW&8PHDPs;!#O#R%qG_n5CVO?lHDqUE`AGz+IO;j)9qQvxmc^|Q#4}B4hKB0l0ae=+VWw$1WQFzX#{=55ZY>~* z+(M@53`yq&QpY?I+qFd~Ssm?T6Q`fLM^t80xb*4I{{XI{xMZ3oc_Rq~az>#dXKm9T zmz|^%y!YT^C#GpiR%pU?B%Z=aEc?oqjKv_?w2;JLHZZ2XtMdS+}xpei{zGE zDRv(~264|A=}f*^ZPHl`d5|)!QAd_4%zZlGdiL*4L}~Yl<;jediQF7+C$F#J?^hKm zF;lA~#$3-Ou0RRpGZuKy3&(PLRnn1PLZ4_xR4k_I(lV*Jagatw2N}UR>r8Z3iZn>% zX?(+(8HUh0lgZCs02!uR%>ij0q=i^HSuNWt{0!t00Kw^=ydKrNjm?~{iC~pvmKC+L zWiak!j`rzeWl^2PoMDbR1HT>Wyry5YEtnEU0u9lI+|0-BoDW*K`5O;do_qZ&;~rtkuVS*rClaXI&1@D-`g5Fq9sd9dkd}gLC$vpX*;+XyI+d(Z z!kxfH1eRVmWyd+`inBe;liY!}7jX(kvZfVPIuJ3&M}Je_y+J%zHg7Uq2T1@~B$4=O z6o5m1E6#nzIVBTXRW&ZOjuq#f-tOg3%48-+`H$!`RprgJE+z7;cG?!QD6od)qg;r)Q-GJlY)Ag&D%siOG zIC++6{I&|JRY2%40KxqI{c|%TO>-Tzk{CCYjU9IGkJsum`t_&WBvVCj4cu1d)z@LZ zW)ShzovKd(pCL46Pe=awbuG%|KmPb$| zU^})j0monf>rsX#DU}fgw3B}NL!H?e#xvORGu!d0V`;>j(paO02>$?o9I!J;(UJhh zIA5C_nzY(Q#y&-%8%J*$h@k!REQr93%a6*TiSF&<)JZYP5i#%I5G<>ajCcG;)4fcx zv&xC&?={c-5}n;&zS7 zL=|QpQBb5{=O=@bM7VCUt%Pooyq2pdGOJs(jLgd* z&&z;tayjH4f~s7|!f8C1!$?@*=NohDR~V)ds_sV}oL+AD143qzo(cj*vhTcVMacwI?hE2T)2j)1)IqG?> zYe`<|F1E)4zz_#{W!Okj*d7VSed}V{xgFGyTUs%e{%O+T13?=BM*jtIsZpTpM`2}K!#K(boxUo}y-mR#g*Cm~z5asCx*3vmc& z=Z+$~H#d}w42QOJoRBax(~9SnM5Vc;Da8?6%-4w{BvGyZ{az|Ba_dqR34_1i)j(h8u9jvdwcM17Dc(5bLJ$3vH3=M z_atCoV-=w372J`?h(IA#6*m2X|QtXqUzk~HILW%ecCGc`gjb&nkB}A1Gta zIOB2SC)Sa2!zCTd^2H`&ic<1i&$VB0K4Sth2=`!fk^U83UMzk0R)Ls=G7+_MbDqQ= zc&Sm;Vg`?CeXSIq#0cy^pW*eU{h#J|kj6*_%#J`-2da+yhbNv780M}qx-oQ;Be}`A zlg?K8LbAThGco6{e%$+-L`l52OL$eT+CabolFWF=UUDkLQDyw4mm*nrGZ!QeL4%wD z?Z*d>XnAHO6@E~E*Es4V9AJ8nb3=uY-8Q4K3QX4zC)#3zPb#sh+t|ROFcn7_z!*5e zJx)pMOiwaV6Ir01X+SYW7~FdLc0Sc^+sm0%C%BF|nHgevfmV?7#s+?DbC32-Nb$lF z60kRz-*icI%DBlHJ8*qS2ir9U5{=nP-c=*YlI!gXv!C57?PZW;VBqoxJRXPXOC&NY zNY^MVZXtci719!Xz6!QI3Y?E(DWL6^Nh5>zrz_@_zy}?D{{YXuNowtBaAbJdo$Vc1 z{or$+ExX8_03$4BoZ)L02Y?P z+`bi7G0s~&f1i4Vq2Dz3d#>&ywuN`v#;UM+WZ;tguw~!?M&FyRYABmfVdp~-Dp;zC z<}j)M0D)li2fr233NdXPU6Ye)^N7M?Wh#j_ux z5)KYNohl|VTgf}bX9vy*7wsNkD#PZ-JPhyv&lJT*-1i952qukw&aS0)x2pr~+k=|T z-Xl}xWRfz?=FJ<}?%HG;;154+5OhKwqv#ET_cJQ1DQ=WURTDqF{vJ5U^*N2 z#F-piz8Vk|6${TN2ZPg&`KtFays#v0qlO-06~STCpI$k^^sai2Nu0H6d(81^L@Fk> z^6ur4p;ZzaljViUKPq$#2_%t>u`*AO_e!bqmDX}&$rU1mPu!wCsNSbTF9}aLy%h=j>3A5`5E^$%^W>8j@Ioh zh$eNCMzoqae8omLPX7QXVtQlw=hmaPIF2}{yDMyr6=a>5#~gX&fHRJAcolwfU&)tr zlSt|n%SV74JqND@essr%c>Vk;`J_G{fbmFFEx%?-7r zD}0v=JSTVVl?urkgUc2pZW}ycpSp9@Q?74ei37kC$dRv^G05DzhJAmB{P(Q!9s)~q zbH3UV5-5-p+>!=Y@$~CScN$x)WU_sglsmlSD*0gZ&$zB@oRg=@$?qP{;^O98Si+eJ zXOUEeIKavGzyt6Vk!)kQEEKzlU9${iZfp#Wy)*Ax32g>q^3^Qu-SH$K0N!7>JRbS< z;;*H=Fc!OxA?1U$OK`*ha_8{HcGKBkaa)xY)@@?qMK0xxva3WOixJGjA$PBK1A=?< zd)0&x-pU}jhzp>q8VJEwRrUN&1L;%TEuGDzLK$2_RKD23Rvh#5b?MM{&%I(8qj`3R zm`5}$v2T=?Rr-!W&OQGCoo((kL}t@2qzh#)mv)!SJWRNb{sA0^C*@)WMhL;r9CM0v zcI9uRGQ4}FW|0ERg=WFy-1}0=1fn?FL?|92H@)h!5ufh;<;D*ujzu)WEgC39n~lUO z#FPx&^u~H*fHUdrYG-tM6zVC&e77k#*ya~-G_fYzi&YK2HqYMA_ekJloP+IKbIT-l zvov!Et`O-0p#>OGuD{iV8rVbcJW6t zDMTMEkmHlb-5~boBDSSIZlp#O(prmkYj14>F_xhh#Jw3g77wudCgZGO!oOiAP;FGG@9Ltp?g)|CWq z^1ZS!l~Ahe$IXL+0qMyYrjv4JeeALBMlmoul~{K78UA&0Cw7+K?J`3Vl~-Vi3aWw6 z0F%J$`PR@)?s8UBmr|>F@oZRBOSVJiw6C{pdFP&a9RTmZpu_fOh0VlsTL{}0#v&vM zjt+VZAFoQXh;EGQIgm=Me#vhp3ryJsLgRu+`G#vg7ii%NAOY>7k!6&FnFdMEHN2fUidR2+;w%suQ07SBQV%%7}Nf;Y? zw@l#YgU26}Eg1)!ByTh#>e)ncNfAOjgM-i!+@_8w6-cy{RleP{C>_NfcW})aQO3!^u@XXSr(>O4xR`P<37FO$?;P$G} zGZ_B>(rg+(F`LSfE>Vn;=Kuf>QHC?~dmfc$D|?w4A`wKsS^eNvE_QQ{{Bw?Z?@*Z& z&1mgj2yV!2>o@ND554nacLN-C#w!^~rb=2C=3RzV-NG;)d{_jY4hHVMa7g#XQgxI_ zLd(5oWgk8;0mglLb*+1wR!Cxr?MjG3%f5ZfAZHy{rsZHk8R^=xq_~s!Q#*M!@T+|5 zk-HobpQk4^actI{t}^~eL9@4U7oP-@7~2YDV0w)8!2ldp*fA+~i_3tyJEBawuhTs6 zeQLJnd9LATV+$l^MhvR1s=x(oo<~89AJ3&}jHM+cHr?ZyH@i&mNV075?F^1iNCR&NlYo6X z;NultZ0_KI#OKLd#6Ckzjg$xb%faKg>r=%g&E?0I&osLow_F>67(a(n@(hH#>>s=fCSpZKO(rY_Dero0Oi_zyVfOi)?YKqWr8^9FEx> z^Yy6;!81ycmS3|gd2O5m-u|N$*J)+W^Kgo}5({Tln8)2gAdW{Fr^9Ll?H={ER)#ea zNH(ca+~b^%GI7t=v2xIDaDQ3wSjOQ!CC$Pu|tyOKUE386Tj@DOl!HzrfIKdyGtogJv zjPEUrhT%YjnBkC3ou*HkL7ex=Bd1TLHLe}4Oic=-x-XX~8;DgrWON7E^WLLqCX(7e zvfHWhIWJ2tu?XL7)8B?TD`^7`6+36b#pUp z*>4DvNgt@=BdcRL=brU-4YFS2Yk4UOw)9QQyo~J`!Qk*uzZu6grH0}imsXs zJ$et9@)ab?$qbPnE%!Q<4x4~sgP-MCa>_jpcOFJX4ECesC6TV}!(1%#ZvEf~Cw2yZ z`u@~;3lz5Uq|&4zBWE%E!B;&x9uFY*=AD0I9F1jg$s|xiAd*?|5j?@kT<4LD5)Y}V zZ6aB2t{^eLksK<@M3am#ahF zZjQ#*Pdvy1$+badZ2J!W)e(qH;VqDnuro~{JELH56b^(O-m6ar$l-xrQTE0$ zNFcZ|$k^%w4pon0Ijy4|Ze2Q2QY|w_Zj!MKp<~+;DJ;bEpZ@?=ShqfAodX4tS&^6b zkq}AhM?E`!A6n1-;v%$7F_t*n=T00SZ1+C(Yfql>S~D-5J8deVoGY^*;wJ}_?dw-$ zbvPzy`D+HA(mWC}u;j7w#^7<+2Rw6*DuvJ6Y*OMS7V%sxK`qwm*gC9a22+E^2q26e zLG(PzWxJ4W^G;bC%vZ}M@JJkVJ^ei@8SNpsj&_-&k_KhW4IWEKJD*%}k4$x>qh`## zn_WnuY{BHn`?oP|>PP{9I{{XJ3OD&8yc9t-t%q5VO zXtdW@%tMcv)D>37FbT=$9Vr=QM`V}*DsE-ue8W6{O4dB76FAwH<@+dz36@FF2Hgd^ zgXuf6l%U$$Wzb%09*NwTCkErKY0e{iSjm25IcPiIl=lM~UUt>5f3ZP_Er6x*l=d2EgW$5Gets`lix zFtqF>!!}fWxNd#<#~pk2srQLtf_N57KPphr!F7onFV`h-2*}`c=j)r$TSYIG6bH?n zC;8bixP!(A^P)0wIuo#qbs3n!GZuA`l1r8(s>i!I;2*~x)g-s7KGO=t5s(wLNc+oz z1M!ZBk@O!*S(4chl6OrUq%_4rW?(zxzkZ#KX2&cStqa99+*7f{Pdp6~Jwf1rdSu|$ z`$i>EG4UIe2|E^W{{ZV3hTNe40FzIOTuAfFE4{lrGe)hofbY*eeg6Pj*9J%-d8{S4 zRYYh~O~Wh+!QgaO$;k93sYwJWbdKRnXsoj=Bo<(K{Qm&YdW9y(%^Q$KXvyZflxDce zD;$|ne!iF$3a%BIqh0I5upclT!2Lfe&=6YNzI^#UcN-KCBv|v$VgV!TPl5<$o=6Vx zzFRuRSSe`7Trn5~^d0@Ut*)$RCGQYh?u=VGBkeZwEQ*W+D|&8IkU{i35GurTMYdst z7n{C7m;jEaJupG-Oo?t4cf$#HbxsaW@MT`it;d<2RmdPKM#7HVKGMuX@HfKxF2^YPkuf7)j4gX zkIpR&cGA3R#uokBs*#+G{{XXsGuJ-(r`d!N%$F)a7R<>wkwzOllbrF4{$S>*(@|G7 zf=LaPg``OFHN(p`*#7`^A!lLe0pJ1-Jw0neP;B-j_Wo7E#Tu+~0r_bg`=N?KB#xz|Ns1Qvv+K@2hw$lKl^?uRoQv=n95g}` z<;qyB3zYkwIA_9$NnJhTZdL450EdIqT_7zP`AES!PRzmOGF<=;S+s zvgZVPG0$GU_@dtK>r{n2(F*yItcB7gg;@qb%JGH(bDl{#>T1=xBQ+T&g?qbQ@x?8q z(nlOSr(_C@#Qy*YW1mi^fN8c(HN0{>iwuT9e7U3Css~UodyWAkt|{&zC}o-1;)Xz_ z5kUm>1mm6$1oZ2gu^b2$QHqfopOi3QihB=YYe>nnqB68>S3xzrCLugBMp2m(1z^kd zCj-B4LsP{vEMw#@9v~ZPGX-PVW1O$~%~df0JdwllFOpU@7yu{~t9E2&cyPrLR&4E6 zMj8Hqdy;=Xm#Q-)jYOh!jndLsq$^=_cL|YH4vgpyNXW@i*VdmJ$t-4QoWE9g3P$Dr z_74l6N^I9JD;Bph+Ok`gl&Ju!lZM^?%PC=xdblIrjG5WFRc+EGBP)*Mv9CUHN=BaY zBjFvTGLI~$?{_KAe!1z=p_0(d^1PQ)!wWagB3=7P=l~=G_0RID!o9p;`S48LI80K%k_N3KT%A7k6nv*zAzBXwz^W>4L+F&kK8aASfBw<8@#uN5OY zER78DfifcDt)$$5`e&;F)3;+=(~PgNkJ>H>t?wm|?KbRgEz!3|vTcwl!31^S<3E)n zyh#I19Gl`YFbK*r4^PMIOu}3uURt!MW`uDd!Sv*HA45?{zE!CR>g5@kq>u#yKYq2= zm63Ah&~uiuf)sRE#E(-9@$YfiKNtioi`OH36bJTO!zH?PJ zNh{`5WO#}B$QwxhpN(M%sdXZ8O=w?>5?aVjocHp?gngdV3e3ImNf>T}HJFcZjLi1Z zF7{P|-H-_wu;2mTKDA@_u?ECuV(M5$4g(Y41du;JdXnj4NTH6_IRm1r38iAp4{@LK z&{olkMsb9Y>#Rxpw1utC)iR?DkVkXr%@9ZX`++RV{#h~NIRRE|cEKR^>M6c^8(+6v ztWOu3%IcGd1gN`QGY#synYyZxociGVRA8j21ermUfE6lK%?iM}=m`bj5 zgU%0Qn$B0b%%vXWw=hD|!#?s%OXbGdD$KqA01n@UIg%jkBX8b?IFdFB!aj4)ze=w< zT%w2BACQl?iNR$g@rC4(jPvyMsNz4p2&Bq|50=u#6^j1=v<`nN$w{+F>RIzAwb>=S zg`_G+m`({()D!4O6g}f!$s01n!QGJ|$z=`6Dmes!%_o^~(X2MBZ5&@JkoN1h%Tvfh z{3KvtkEd}{-CA5)#c6XiGezeK3WtEImGvH=f)0J^kV-Bj6589Zmo2mc*3lbk+r~Di zJ@5~1wI7%wQqnS$AU;W6paaHw{{Ww@O(op22$k4L9C4kj4oMyV09uYaeYt5>9S8cp z>_=Sm;OCA%t}2pj&K&Eg_-AH{TWN_YFF<4@oOC>62RX<80A8OPM;b)3$mtn&S7nRL zc49tI7moc-cpT%3YsCpsC2*JE)fDEHOLH-`YKK}GH z(cGScWmkd*x0XM%$s;Pn)1X#TdCBfU6&SZJjT_GKm)McZ8v;XTpKO1PLLv_|uM8I! zvEiL#xtK`BeRGceg+VER0}IJ;(X{8vx?&@3ySso%1PWp;)4>`Rk}H`Yb}GAED{(C4z z=xTR`U@??<#j-ONay+(-_bh*jcHm>N$?sO5?C~olrS09!w*WA>kpwLX>9lPpa^s$R z`&2$_$07S$wDJ@4NXic89=!)W&38euN=%7vK%Jpw+Fms(ib+-W9^YD?Lv6geIbb2- z2{Vs2#f2WR}3p zr6vUn{PD}U4m+H4j`eyut{=#0)(It%3qV~6RZ;aPpRZrWyy~$@ofO-Ih|T0L90*Y@ zCAmVa84Ss|4sgH>o^mnBn3e!*sGo3joR#2!hNbK)p!G>CIIH?s^cEW|;9UoRc(uYN8b$ zY_|!xDB$O&diNC7Pd9YoR0!Ov5g{A6>w(`q)eX|cGww)Ck>z9xODOst<2~y_-Z678 znJ|~;T$Ws_hw5{h={alDNqG;R^c#`4=agy48RCRStlxC!00P+So=M5ctgSqf zw1U`ztYQU;Y#!YQJQ6?p)acz_;qA^_%<}UDYq_L3AYgi)aBAd?ZKiu$IN67qJhgGR zb92;^06yPZhTXP2>UMG3i z*WRv=GBM=eYIisP05D@E*2Xa4V`A+9ZO%_QIX;-G^B7AzMgk&%<&2Y&T+`-HW40++ zu(r0MbeVM+?xIt<-pV$_at!>87!FkYtVeK2sBTu@&V_Tb0lAnbW;H3dk+7EU^Q>NE zy9rRMzy$s$9QxBz5w?Hd3D29uI)xy2>FrxWs(X&mDx^`*Iy|0SDDa;!pu&uQpYxi# z0xWRtf)dLSY%@jz@zWha7^>0vQAlBAnafEbL=ci1KAn0F+(CKYa(u(+I-kO+{{UxQED}p)0?QOqgjRg2s`n)0JypOcB zWmv|$v&IHL9CO?7q?MG(X%tc<#i9o&;Is=uCR`BHgZL4l6dBR@B-Mg^qHn3yD{ zcKI?&sLxL4+LP@ueYIuDYjycyd9oWA#^dRe+LlI&CXI@!k1|i)oHGO8J?c(X7TKxh zF#%bPmA2-4hqsGyG7*IwoRORYN#JCR_sw`Cc_EAi+Es*dqaDQc$?f@5;AXju2V&92 zS*BD30NMMw{GhMlPg!I8O!LU`5)No|H2B_QRG%orS;05jYkPq3(>kpn%f>`vQ{o?(_{Vflim zjGB^LI0TCXattDFSlj`ebOZU+ZubSe`*{pA$#7Tw5>2uy6~hm8e3dxK!6S^;dNZam zgn_4ME}^!GVMLj>t3wFMC#OM@JVEG_$K^@M0MtG#V2ISe9(|mikD{o+})N%)L*9W*9aa6Q3TZsZ(wYvsUBzEj% zN##-`W*G0#=NZB2+pSohN19S&bxrZ3%NZaQ8RO~CKb=HlyCyqe(p|GLP|22gImpNz z%?y$5x4L5Sqoi!;>Pb~69E@j<?C(l$Q~9y9nFo-3EQXd{JuwiB}*!)`z)ADGYQPf0?3r|lu+mEEI{ zYlV(526qsDE;-2uv8?@^S3?;}Q9y|d(c81512dJ9cyJkH9D&YqG5&d~@GZLDExK+h z%E>CY<+;x6`tjS+n2#Wdq)*&oiZ)zz=aJX9KaEWiD@z&k6)t?O-)oreUBsN{spGHX zO>(AX%$n7Xy0-FUo(7DpPa3pBS0^p``X2t(`1|{N{5G|5j<&+gwQP&5vcLTkAfBRneEO>|E)y33tsFu_&S(j@C zT$101_3c+tItW85blBV30F_ay=?7VeF>W;?|B8*?TgOW@w9Kg^+`_k4%7Z=tmW;;hzv|UI*}wtFPE4jnr_|+5*v8Y8E!C z%_NxH^Wy*pJTb{2Wb;h5zSLya7Rc%U0A|@H*P7(6WF-8JjO2nj9@wvAzq|0(p`&WA zu3N@0?=R+P(@nS$$iQ+oFa!*edIC5V^XG?~RYcT=EpG>%=Nq}(9$Q98193liU=DlZ z=~-8$K2@Qf8x<@c4I}uA^w?%1ISdQZ5=5DhX^5Ny_y& z9qZ^1hq~~%@fM?~xARHcZ*1UT3WYe=ghXqn`TU{>4 zulPeT0#!f-_zIAHS3y}h%`-qUGq(qwx4vd{{W;*Zq4UR zr2XdHP7fPK+z*s-oSNl+AIsod`%O;o#0?F)EFrDh`HHGcbCxHl!NCI_l{S;%&kt%) zYZ{%ehzk9U{J17~)n;ZZov{G8Wx&ZN0CEo?SIpyZlBs*7&g@nuoiwE-B-g3vI!(5p zZ=_saz4XRe?{?b6@0iya2ftpNW1O1l-oZuW|K9%{#afgK|?fIW6iJ#Ugw|n}YyYTMtT-@H-NvYddJeNwVe{l<#)lc_= zg4i9v1lQbO0X3~o!%x?=g)c3f&e%4L%ehJ9slZ|1p1jw_-w*D*GP*{fx|Om|t;`GC zy8|;7JO*V^lwiP+4_*&S^uL5Z8+CsL>-TzvgkFA(V4BwENi7wXhau5P&ek8r>`3p% zxjt7%+R~Luv5IefUA{>9>}D!7sZKG6y>6%7{{RL2XX0Hq#5&%Qr|FkEg}$wO^UR0$ zeqw?G3=zl&o~I|!n)Tle=sq3sF1xSEtzKE^yKLF6()Qs~6E7J;++cEZ^yAa>drtW8 zH-|iTf8y;L>fXv3t$=Mh>ShYnQw0i*KD3Pv`s-R zdq`4IZEG$601c0) zZJ^TbJZjL-e7Cw?mY^e=>&{Ul!;&`uFfw>N4{G}};r{@GJ{xK}zO$sQ+&YJsZi}V6 zxLwe;cLiMIJvbiUhv(12n|m9LYVS$a^$6{L(Qlhqw7FJd%E;-%;xS)V zl__FeIb*txx_?~@8n42uh<+n#+BKE!i(1GKX-J5vvM{|EspS6vlbYt&;qC3KYV9rh zdAcO(x0bL-8CFbW5O50)z>YcXUshQBDbTfTds&hle(|N!40h7RV>?D8W{fiY>Olks zA9UlWJkzcI5y><@EQWnXLvcOUA(3OlNrYBX#OFE4&Oe=d)wms0t0_kZIK{VR%(`{l zRP(GPDO$ECnrSbx*7ou|Gr(UH^*;*>OFNf>T`}%=O&Nh&PeYf%Jb(rd*S&q8;qMe_ zdi|y9AE+IT{#C8J{-kI3tCT?Yd(jGoMbb_ z!B?l(dmo}@l6PqG2vy*L>(;4DrAA{2ikveXu=TD7N%1|s{BT`a34YHY3TBdXCgum` z8TA}wdy4c}uWeZuWQsi2wp(dpXo{K2 zN?4Wps6F6<*-IbG`a!x*+dkXr}<4cBC*ztmbA~$U(13f=l^Nnx85Hnm$ z=EoV!2%-R%3yuln7$=SmTZC4pZ9G)2v^)wakX<{?8EuyGBs`YepF_?nwZh+F4eG-% zhaYE1V-c#aKo|q_WOY1b^IoF96>||-B8oIHg_CgIxPzSJjt+R^u=>;z_*&&HjN26b zp?+fWi2~!;50|;Y=CPEcZ5i0B(LCza;&hosv@k@4wnU(a!*u{;l0xy0YVs^Gm}7z> zZmyx)iV(9C>-hSA`s+sPNEY(2W($~CdJ(xw_Q$#P6`ID~ETwCkKRH$&V{|JcG0rv+ zK@2z`oM4Xi$;$bxWu%G`S~-!VcZ%LXLdOiSIC&UyaBx8w?d)o6D`^G5kXI@u zn1ErnCd;Z}w{-T;)~uKV!zIL57~3N>3o?c*-578=sn|B-KrL2M{DID!=rWR!&s*#l^J%}S8kF8gb$sCcG z)_;|hl_W6T+~*j2jMb1^660CUf7DmS>f{q#mDreSc| z;44O)oUkW7a4<5 zgtMi-8hFje+5(ckQEWGE#~AfBNZrXa%Nt0F2VQVU>&9t=QdwA)l0G)Z&i?>1s^hOtizB!CnPi8jeFj575-dXl{ddh_eo=DG72%yrpk#A&rf#85OWnN_&o zkl5!r;CCaBO65~kxB?dwD}@7T0PR&HzX0*+U2XNlYDRCh8)=|N0^THp%fjP=KpGU5_7;ifF9g>el_RXEbwU;s}vVE7ee|d;}*Jw zsJf9-#I?PFM=#_2LU4!QpTA9}~V zGFgu#tNHjoT!TAy_T#2&LI~nE>o|f;%Nb=rOmb%&3>+Mve_zJBX;qER{5@Gh$kU!H zyA~K}ZPQ^{E!b@%IP1oG9{h7u7T{*$DQy6aqg=6EtZX`;ae-O#iKK+Bjl+mmMrd3) zZKtCtJ$N}B=N#2rTZ@JdYSKXR&ma=HbFgQq2ON+;KVe>tD$eIkTuj_nr%7)-Y9N;6 zI)J~r^3lFs-7*J0hn}CEbdbyTs040X%o~~@vlU(kaoiqwKF76jW;B)-vg*46&nn7Q zfb|4(_=?cAFD@sYzHAjwEEQ6{xb??V-n|-ic_X=v989B89RopdIsDD#@ehsA83trOiSmHgOjLBzIFhR(B*Q1byxJ$Y45g`Brlz zKr^Z&w*;TGT&Vrz&DghX*ud@3R;9!45*u}i?aGNHltxjB;9!H!K;Y-nqn_F&o?o0= z?JLQQv^_ayWyv_>fDT4|D_GWU)@GHlOItG@;xTOyMMMyoeqSu@!yI5>`g5QDy;Ghj zV~S~i*9Lv41D0H4(>!(06#Zsj-Om_cru(NiC8AxtU>hau5at^e3UmLG4|9Rwmvwk|~wua59p^ zg;wZ0@&{a;cdYweF=CQGwzAvGRaDxvM84629Gn#ZgU31c?^@Cbq_}50Wr{M28IC|~ z91eYvv5*MkgV;2k;fk+?i5WgKD!wFP8Ho1`NRRatQVo4l>x0%&f%l2G#Q`aY+Ycj`7n(?K!ffYh;X+zDo{7J)yS=j%Kl;&5xyg5 zI2awzVOp_T%D z-8J3J$|dveOeZfn##rZ*j;FuYtX{m*O(Z5bwj@fhx*i#TG ze8e2rJ0803&lR-LvB&Shgfl7=+q#_NpFl@?d*55Q4fC@Z_LKKZE<0nInNvz8w6Rl} zv2{M?ky11Yv+a%JL%87MoO}NOT8(4-NF|V#4Y{I=0FnOy*V|E9nJ%OC#gc2Dte$j6tn1<6JXXIdxK_0{r>(adJM=|Q*W6b^H{iIDX5hO2bZwJjj z^PSo4{{Ywbt%jO5w0PsRQ~}v7XXI^F87REt9D;H))22>w&CGGbZ5+8tXN~;btT3nB zr@!S^U}BlLA7>46)o2_ew*giaM&eBxGb9@(AhIG?({L8<}m`WmFYc1bo~BoOUDF z{{Sk;lUn;U4mYDIQ}%Hi098RFpy+x;7_k_Zc1WH$2ZRb!BYfChIkQG!ptGv1jM zrL^THE_~)s^_%vcx%T>0Q^GccxMhvyEteTPGyKQB62$;TMVuKUwpiX|z#=kx!2mE4452olSpz9w!;JI#(^A#pFL5Hu(2_pS7$6BYjF2{_OlJdk~0jbJHnhEyz|X6IR<8oDyc}>qw``4!2bZf)bWnK{{UKoOL>qo6U?}lDPWUqjM4{Q{Rqe)j^j0P&~2nwYbfp=LO%+legPjh zVt)};=yt~`;$uHDlCAy&t3gba?{KHQy(kWw`i^NXCK1g40BDS)>{+KFiv~UU>Cawjq0MsOuOcao z233f2q_eC^`njIVwTtdxr=a;rV zWwJwX(dCK9&Doa(ji-#@_N^&4EOJFEDnyKTDut1nL6W=^f&tGxzZ%VG7jw%bo?8iH zRLN!leKFI%YFT1<=eK7IwnB?0QzfH6-So~gpGug;rpziUksFUbKiykQfY#QO>hhzfX&fT#rmgY^RxXIcA5NXHG2-?x9;~;_tc?TThy(Q4Lx=Gcdb%Iq;_VL}c zY=6CnQWm+L!Rvnb*1Y-v$9FjfiD7@6jxWLA6RCPVS zr!`!WzUGwlko9?Fw{(&it=G;UX0nX5iUv9P*q1oqbDZ)?%|PeLC(Q+tTo>A;ZEXHI z81Gh^W!myGhm)PVTO={>?@>oEi^^i|OUoj>ZIV_$<%5&c^5(PUQEcmD?mVQC5hN}h z7kjFX2dTyYsxnNXNZ2q>vj$gX89hBJd8f9L)^~B_ z!Wn$Ov`7M}AH+``I*-Dw!c%1 z{=Fv`7&LZ5%+Fvh9w!ebagBkq8DZZCxaX1U^r>PveXx7s|(L&X@0*-_4A)neHt!TtOwLtA3lZE{^cz6UT5`7rXJ})@ zKYBF>h3rqz?X5kZGBKQakyys-bv4B5{(G@v?8>at6T!jdxE)1DD@hx(#w1~IOCK+j zoZ#maiRJmGNuz0r2V(h~LY|+?Kb>5L_}kp6wV1+&)=1=<85kDa2q67I!KLi1VFc6l z8Di}<#M4TFZQ@Yd0-Wdn0M%2@Sb3Kgra55&n{bHDn^nSNWzA50)SPA0FVF! zKjZCHLp$C5pi3l|F7g>CQh5w|b^7z~P7dd442Zx}vA{c*{Qm%2o;O_Xx4g6y#!sJU zvA3A2IRx>y2kV{>6x7o(vQisy<&qW?v2X>#IRS%Yo;k@F9cnKnLcD+%V%!$s?ezR= z)y#6+kGLaSlB}%baSD0-xvI)-!HoRZP;UL=l>`P;pU~s+r>u>mG}#>LXDnTk(lIVK z43${P&Q5Yb?UC3~HpmOID98hn*&dapWpJ^|XM^`}g+IEvaU&M*)B%j=j>C${n%*fP zFLcnzKGB4Ul(Pam^u{y(c&4Kwn@tvBe?NSiP8T~#AZ2Rfm-}pTq$sSCsKAo|sTcqN zInQ%hsr!=NQ7)6I-M9d;obVUacggi5psRN>znLAnZIcQc&g3WqsQUBzRdgqnH1sb! z+uiMX&)FK*@tEP8%Z+eyNzO`+o&9=&Pq+}vW{G7JL*{<-&1-=$BxgN_0siUd9sAW8 zT~r1@7DQ6TBg+B_<2lVb3x|qXWHIiJR%7J`0YUT}bR3>@Q*?>;F58mE8f3SQ*4Ar- zad6S2K!!$=Me3v9JY%+M1-oEmXo0reTY-ivC$>jS)EBJ9MCo-B#c{iJs*&N1n~N9mIj@j;HHNQqZVDMT-nm%N%meHO0zHD=(jL z%-=S0Mo*?k1E3C&_=r3{I#`M=3h1f#Yk2e8*|BAe;2sTN@*Q2oT6DbEemd*7+oi2*ujK~tMdZR z0mwP+f_Vm^xwwLICWbwMlx+|4g&$7eN{-Un7~ba)LzR*_9d?jgBaGv(80Y+IyyVGn zV_2XGa_7jlPn+ila)rq!j04n~>4g2whZpXXjj0ilBRke?G@OirKhHH0k=Vr?f+$vL zLddZeU@_5;=i02vJki?5@yKJ6WMLpjAa&>bDlpz`Z*dw3qC@_ra>c%x{7)2Cw;lODMvO1D6-=6)yI&@c7w^Dg446(E&R#MTr zt1({0fEaQ)85zjVL8#gYWVrGpG8{8`GM}0?0Dki)9r)mL`B5A65|zh5F>gF3rY)jH=TN4XxLXzlChx#uaLEwiB)$-|sTWFm|1+ryPv?VzeIV ztkO8*D$K=MTqtGT>4TB^(!!BkTMJq3rZBMo0ACcv7;(y@V~^=smyIecYag2mparFj z4qLkO?ZNu+Yc}G=?Qdg2mc?ydC%K$zGe}()DNzI|J!&gx)-1G_I2Qo4F_07>9C~{C z){$!Fk>!~mnIvVwDE|O3+5&>vKK*-i{{R}%SuLO<)P#dR1>S zH<~4$IIRN4e9yA6lgw^;%Mf$WbQ}(urdyPh!x}~A7k}gFk5lLgt*jEFnh}D@a;(zK zCtH6pV|#LAWd|4y&^Av)$pF-|M93ubS~l~PZBn0i2S4HdO;0QN*DY`MXsoVQ9n3AR zOqT0|$}2Dj1E0Ou@HL+c@42|QnlQ*G+X+c`61W`n?%RL^J&(0!<#U$KAS0gQ-YcIj zHMevaSlDhL9;`a4}IKEZ{ zw+E6rALC6jc`5tQvx|WwV8xXYpKwP!5;#41=|m@O&bl*esb1C=Yd4q9nPa&_ydo;B zj0YZvjP=hM6(U+l%d*)L^5LA7va*bcnTQ)#CxXYI=dD*O<|+Yl!2UJ zXBp3Po}Z0O#dfqx#wVFh*5!Hi&#hm!i|ThO*ISCnAw%|@EQ+HFtQtfFokq|c|9)O0+bZ(P-gq>WDCqDfGOd@ffX{ij)a_wY~tD3kzIDeKwl<6${W+)6g`_XNXX!q%O(lP=lp3a zoiJ*{5_EU++8H5L!igPtEXVOU6v+f=+f^BhZu2rr1pxIYrVemElz#ccdBgXy$_54) z6P$Mbb!JkmvOwNoickcGJPh)B5y(FN^|WWp5y@PpQxZu!oD2X7BZ18qR#Hj(o1$W3 z7t41+xnnqBKsmr~QP}n7pA>KhnIMuzh_CK`(VfkM=yQWqE?^Ng%#lefld+G@kV;$3 zQP=~3r#S~5Mk`fT4Fq7DE!)}K&gvi$OLGK`ADJw|H3RQH9Py5wI*=;V^X(5N*xoo0 zsJCV;S-KJkz~GWbc=gRXD|=tDM)8?rFkz<+9u_g5?`P@McQswbx=$;$vhfRTlm*;D zInGb?tyP`%3X(|`GV3JXTNYKEU>-89*B?ycr9`(fx0xjVWWO)jWkoTN2q1&ka3iSo z_N8edk``oA@U(f7Maqz;^2a1oBx`alzjOw|JcqcG_nE=Y2sk+${vTS2J4Kn@7KAGl zvTjv$UD=GBkHa3Fe+sPP7Pz*KDU%lv{_=NM3kws$U`9wC_Wl(#rbK$g?`V`wY_dri9E>p;Q=a3mPg;Du z#HV7Mt-4sJbUs`Rjq=1?vlEPC2ae}FezZgbx616XO(*))0kBl^IrheB@y)VrtfaYx z)iS&Qc>cMnu|;y%5xTT7!;hRWC5rz5L!V#kRH(azs!GN6c-^H*6Mo=T4sgp<6%{3t z)$sGJ%A`vV-DTP^7u1eMM+D;)Ht3dTNaNf@tOTYdSqkTZa85IU#(4ZQL`iXVZ8UOu zamO6TYAPQwThu>s*a6c9wNPoCYFCjtRd_^Yq;_OfCjnc`Ilvh9?kaV%n1-17O%(AR zqs&}}8P6H()BKvI(fN>-cDRlpVUev~P)V6OI~;S)ap(!>xw6dAY`Y5HPUcw7-;~I` zMtU9!=j-o9N1@dTwve%{rLd1S^Plv!Tf9nCvUS4b5Hst8`czkG8{J5|Bq{RwWMlw3 z{W2;RyIYq=SkyDQPcS#iSQDN)WO5JF+OOSRa9hN1c+KlzyU$d03YK;&APzM*D^Mr z3}!Rs-Y(Vz^SJfkj1i8zwre01B4Wf*3!RA148U0hhn8 zBmDKMw$jHn_nCQXe32+^klSAvfs^4Z{yyw%t)6eGl4W?0zyY@iaVdV}0x z@sF)8cVkGxT*ze4u-z;L&jcR7T7z(=Iw*U_HXroCab8cBAF%B6(R3MySclSU3x|EwRto`yFtTQq&Hw>}x zWl*eFoG}349{h2iYP5?5!>njpQy2xIPnhmJfsVCX6U993ESbXXNAofQ^YVe|l7H{2 zV)=;)D->;T%b5@oH#csC6ZNX(O`J}u?ku|{DZVslLLJfWC7Mj|0LD6Gs{ll0^E|R02k$(^I1Stb)Q$nq_*As6 zU&ZKJx{BV`X)W%=ZF^^V$al zvnSf^%z_d(4ail(@r;AhuS3$E7ndR4%-ezGcXvI=q?CD4obGtiHfP#57CHC+wLDN- z?2c$dt;NHWCL$YLfzQp?Aa?XWO4c*xW_2TS7;SMYq;Uxz^9!_MOn}^BdD__rk;xeB zYRM}UEUC6A`QFNload2}Iv$k-vck%;$1sVGT1eEDkSOkb0pxn|+lqAC$xvdE5o1mr zxg_)d0N4C#l8vlXVxocn0M;yEDzY+TP-rOsf?C8h&+CO)~b+#Y@)=> zCD`tOmIKq!gX%phOvbXw4$PSW!$#XmuVuF&Bu8eA#c|BZH23KGe5h zDU6~208)Nw6yn(%0?t@yc3R?=qdjIXfsbKc6MlRvJsHX z4_iI^r@zn zFh6i7cw$548DjF;hq%rG{An4T`Nuz8Q6HZ)Gut)B&E;A}Kn~D5 z53jFYPqk8VF_OPRE1AhYQf-LMAXxWhl}H$3NbU5`<52zRqn>c_T||S-c!H{(rw5LN z6&}Z*UTVV#BAR@{@?0gTRb`OicN}{A{{V$3jU|l|L>OW+vS5Q+De|&ZHqeGL9wfZ; zZY^01f+;Pc3`ih=2*|)a&%a86;h04scHxzLpa5f$)P6ixjB$vhxLCmQ%xfGm?aC+z zIUI4$I(GeGX!jlY41t*smxfT@)zGH~i{^0|2#q5#%PdalpsL^Hw@NxCc78=tPJ_ZvOyiMorUsw!s~HV4oK%6M_vtBOO-M-az@*CvaEm{6UoQnSw+V|Nv1M5;!A|u zb0^HZ)NNK$PxSt^Z_bSwBiI6yzE?(12qM zI{gK9$70;BiQY&-k~k;1aTMjyTZf*nDLI-0RI4<^@V9Pa!+v! zD4Hf6W+L5mt&?9(8+|84p~u~cP%Ly zE6=AxpXpa(k!6l1XDJXRfZ%hCbKHz}tb5i=HJz?*V}{FNX{43>y`b^;y>Xttm8WkN zta2M>j^gGlm5x**60432aC>pQQaXRMG5CHWp7N|yDG{^Nm65|HGFF1(3u%+hiP@c1 zNGfDrpyRRY)3r*j^2V%JZr-JG%GTd6UYYH8SI|9)zP8jVt#(AjYOt_QJ z&cz|d(en<(_T>6eZA_9yYlZozR!L)n$qJLB5X+t$1YnGD{xuMe;@$;QwpIj{xyKQ% zKJ%WWcE|q!UZfJ-2MW?da9laT%8jQzx#VZ_s_Qh7+Rr9iHY!bkBjC{dC z9S540W2xuc=~JXINQd`J2b`)-2_QE-^T{14XNuUs!XGbc z%)yA44Y=nVcjF^Hxb>{axA}i(hVCiVZbthcxMh-ZR0=L37ro3Kk0!NDW&`gG!wWOuYJE?Jbc zk~qsK?!Ng4y+tLolUwf)}4ohx4Kc=Klan zj%mEYpL8G`o__)jM1-UuNf<6C3u;zj8intXj(E=<`qZ(ql#XVaIA=4+tgMBMk>KqL z2Y%%9!0Fz)IgtINif~4-qE7sUSMyYG1D=EFjMHL3vk2lIOw;6~I9ppL%-A$c+1#PY_fk_OhrM7*aZpzDcy{Z)tS0ENVs6SraP!+r18dFVEJiz}SdSEzH3N-!|S=0b?bP0~sWA zB=OY!YHO+5Xw_B-U0`)okhu~DB#Z_A>FQ5n2d!Zz&CqRXHw^O$O{{kiIBnMLxnpec zgS3X@>-^~%%#p?{t)aJ1JSUc{Rbw4aI3$2RzL~0rDR*?`nGpaGl$>Fh9FodMZbt{u z=BA3`ZKi0P33vRC21ed_$N9}=$n_3aV$9Z-EhINB_Bf@DSwLrInm|ri0@=XhIN)Fp zK~QRUi3s~xi4 z?}lY-hMr>ajCDB213jt=Zp(7K*D|^zOBzQ!6A!qcjE)b@)PP3D%O-P^&_8}MF|f&<>nAd;@NKHwqWYOMu7_uSmU>Doc{nSLeoOg zi6cd8sJ9)doJrV!_3Ha1vbp(3m2QX3RUv~g9P&6nTAJ7-?JK91A2{KQujys$tLul`A^9T58?4x%(ON&vq^(hH+@ZNg4BNXvw*8z-+P00f0|VI27v$ z)n>VscNu{pa-mfIzlALK47YYp%&`m>yP9$dDszHQL6gpZN_dfrf(sGke)K^YD$Sk< z$2|vcQ|V4kGi%S3ZMz$toKSJA`q@7*%PxB1aX`k z9FRH3_|}_5kxF5TCy?HTXFyNO?fCQWRb!4R!(2l@n+SnC;|MJpC^*T_PDlifq>k9E z)UM8Iu;yYr%E+J=keo0$+zWRfhkA+)-bKQ+0c2JU1nZUofjnb9GuP?GSa-aCIOZf| zPcAZ%kic|2k6))f=`CSPa~-K^CRSG8E1jh0+;^f*$li=ByvfWsfJqFSWRbt+pUt_u z)C(+7GQ8u=4;wNpNU|0Ks62oPJ&$9a^=4U6&AnA(c_I+YBd9U$Q^wKJUn7~apm*!g2W{d^jycM67@L2?lz zgEC0R3LCj3@CQz6K!~!mDLe>djHnYZTwsDaoOZ__)YX$En#$t#%F1AoHe!-CF~&{VJIeYQA7k?1j^SQtw?`-1Q_nLnP~R*3#Dxbq82qW*VQCp&RuaIg zBLd@a8Q`3bhXiNZr?ryYd2q`sfCd}P`FzOn&=N6|`2PS(npog%mjYN)NKh9?P7HY< zla7o!fJJYyF?_RSd0IuhHy%==yrsU&3H{nB{uLyWKpoFC*yLE4Z*0UJn1||6FzOVX^%&%j!kRm& zDs2ue9Cp)4u(Xo-@*vnUFvA=X)qVc84Xvx&%?!-&{h-7*h>-o`p1saGXQvf*6u6IO zFD<^#%-hG7Sg>sTqc}Mo3FvTp8nqILWb(3P!hG_aVVggtbIY3hn99oKGNnAI?_hhS zX#+|8D#MY0c){p@{dFUvi#SYevMWh&yM}hIPs`lx9QzJ<=bG{)mlC_ogD^WPvN1m| zsr2Uqk7{k*-NHoacO=E5E95SlW($=A7~=uAbS&PaliseJ6GXJ^GCR`>D2y|ef8I6% zuH5t-aqE-oO^Ns48Roj-gX~yhEi_~RdY_c5bU5T-`&4&N1SU;+R+C*L$mFgR zNueol77s0>ZNLm|&lu#e!5sZ*V)Dc{Qq1AlZP^iE0$c8?JFY3 z*ChV{howb$u>Gbmin2AlMN)NKZ3n3CdBD%mdQ_3zLoKZ4cv;g#b+6%+`eMV za3ElUYoNGQJmEmc0Q2>&OH|ma9M^FlHt`~sX~xvLkdj!8l1b##?xTBXBa;6B0`Zv? zMQ#kADd9-tkV*UAoSyYjWsX+d?9fLuG-}F$iNVRnew>lm`_-9ev=hT_Clk#bxc$(= z?Tq9Dj-wdI;AtVG<0Ok7ZrD(ihYrlP?~Y_(GDmJk4+GMxs|1kC93j?C%_K6f@om6n z92}0{tzBEUwsu(}1NSS0k|0@Ef(Xw-MmZe*b&mH}0(6>4wzSHALOxUJ)7zSfNm-Va z@1dabtcpx*5?I2sVFp>c5lXEr(2%MEuvNsrDyi$ZQ4Ho0Cz)#;vdUNYf!SF`dB!pi z9=@NAE!1+#A}VpP6-*zQz5c&S%A5DJGUazAh7H#MA(5e-Sz>ATG;F{EK+kcU;C@va z!jLMW-do+>#2b6tt1j;NJAmYLIOC6crr&5u+DM%h7;T-r){T{j<7n;(&PY5|etZIV znL`k+s^M6+?DNKQKBQMdy^SLYIFrPXUOc8RI_GRX{cLuyX_?w~1b{J{GC5B05S)3X#Q z&#=G}YplJhnPYD<2ACG|&(k;{`_$39Jf<};GW^RG#Hvhc{-+#}Jq1E;ZQAkWxAT11 zfyj{MSYwVcLWS~Vj%M=6ow0&gG4>;<_Z6(P=yXN2HaODaITl!a`E4$@Z5Jjzta36) z<&+GNr;OsB?o5z1oR-YqQOt5FZ18y){vp?&PW2K`5VgFvRtLI0p8J$GRF$SG&(p5v|d7gZ;9FoVOAaX~1 z1N5mNvz91jwPOXmW_J5D5TRTzJvy8Y-~Dq=hs$S_Na-xG{{XA|I+a-1^TnF0GO zt7fFLPW#<=e9We*4RaLbswG>CowCCcC{_`G^8(DnxL(}nJo*oO!q%n)WHCuJZrfpt zZ5+DC7wU0Koe3OuCu}hDDWk%<%*p(V1gm++(;r(!(?X^C^;h zgpEeom@!{dkOxD^{&gHTi!_ZAvdUwYPxa9Jtp5P}HV5mUOjZs(Q7W5kts%leZwk$E zEb)c7EPyhvQGt?1any6j?V4L@A%H1@*UFv7(94A+9=ZCCK9u-U67K90-a#kt8rU%N z4>=^9;Pf1J6>Bkpmt+zkk7z%6W5_;-2Nf}$o~G@k(1rqz^BEV(k`z{5-6T2Wah`F{ zZj~&XkME(DG=){RL*@wM3(#bq20iMtHMkR`a!BH9jl@XA?O#Fd&q`!dTBNrq?Jdo` ztbCI3Z6Ifk2Txpk)pJFnWaTTD5oLgExwUa5Wck7-4IG_tN$5vCN3A4Gg>ca$L}U%+ zpWz?LPq;IJ$ zT@(4x`A#DnW;~-1STX0Qs^0psS%7CWmHP&jOIxfixCywXOkpDhLm^9UFq z5yo-PKJ_FdzW)Fr2JMTO*oF#&uV3X`6}c+N^2*n5Kbvyily4?=t7btk<+Eyc8< z;EM4hBqsS@257?rl1T#~f;)fu;()~>Nx64zKe}~L7%y@9V--BN5yxlbEBuqn7UZP6 zSam8${vnKv`}@`sak-nPrllFC3axXw%*c${kxY_19u6^_gV!I{uF8yJf=FX!j$~F; ze1;5gc?X|tb^NI|E1@xd@T+V|4iqTQUwmSgVKvmY{$z~mg+ocZXPe(^ymdE{7MZ1xo~Nnfzo6^IPA-;x%OVqO zfT|FA2PZlGc=xQ>Ru-8A5MD`&T;{{T3pc-lX+38pjOTA2fo%oU?2E0M^^7v}l0y$*QKBZEwMgUNFuu_%N$G6Kry`gN$*JDZ6a<&s4%yP3ll zIp_J+w`5XQVoL?*nIwyOa`HN#GIW(yn|Dx11Fm_+8F?Ihh2=;Jw;NS^cJ%9?T4Xk} zO#c96x4E~B-ER9tGBH+F9OrpBUchsoO1UMnS);2N8C}_TETPz+_lI9x*DR}YqU9u! z3IARD@zmvvxk@ZYTc$*G+*0OB7~sV`62% z1va4Sq@MWg-1Mcm4!}3A7ze2s-ZpaqaKsJ&7mn45P z0oNcLbDq@EYPSma5TMLM%Za319A}g5+ofHMG?U!9Dz>(^*i`$<(sw!TJu&*#5U#48 zXjt6Fr1@-0f_n<|Y0X$H+TO&l!jB!qdzyQxT|!$xL6TPJ06V&#f}@TJmRaq-T*03? zQGvvr0m$pq)||GAZXt056T}ZPN`$iHbp#Q}I6s9TcZT8Z2xvUl4y@;f9=-i58m%*G zddRl0TKQkSl(P-VBueF2u6e@_LH8WgOBIZ*E%L_j`L1NYw*;!jSd{=4C7D8n`J0}( z>5}VZ^QU-L8E+>|tg%}W=14k_Gsiyko_(k>Zi;Zzp>$BCl|VfY2LyT^wav>J8Z?_@ zUh>{hEJTYH+Q6!_l z%m{&t40j&j^Pg}2y;Yvh;ck+9V83Oz3@+7}WU1(Vdj9}FdUip}7>Np2>G&k-48EgUPvgE-0S(<7R!vRlAT;*D=}8Qzj`+kYOI z{{TJdEkq>!nOS6s6ys!=WBFE*jnSN{tL!y|Nh2h}cD9T&7lAy*kI)g2Hj{y$e)Uyu z$J;!wEU{=*m0`$I3CCRZ_5T1G(?J`=w=x7VEQ*W}1tW&r^5hfua7gY(dev!Vja@H9 zB&gi6nBijEnC%3C&IWVO0|zyHi36_JLfi~4g~Hq2+C*f4c~2x}Z{7k%-^8+raAX3Mu!J9O)n9FR^Zei+FGUuL8 z0=g;6EXJ%{nkTlpOJOuBk)#(<<~0$Ls4@t~c^LZV^ECs*aMw<@@p+GQ(THFqmd<%T ztOz^-j()WbtZ>h6U5Z@A5(E3l&IcJDoP*EdQb3{=6D+LXIm1fl0CG=Wn69N1`jtv9 zB8G~>Dei7VG$_sXsYHA#k3e&bcQmtEtnjom!8DLuN1vUF&L)B- z+<r=sUw+9ArWC}lbJWP@Sj<_HUA5OUy71Nt{-m&@d0=bvBJmA!d=JHf4 zaU&FwnmZ_%l?-#nIX!b+af?%JoeD}XL|T?-D;SRQNYnmWz>%MrZ8*>3PCpu{FuIyK z?xPY&(L%0KQ!R|+pH4^|{{UK9TXM$As##@ixdoY+`~Lt+O|}qS$#Eny>N3v}TWzu! zBqk~H5i!|H)$nHjgAe)!XJ<^8Qb$<#vTr+N+t~Yt z9FMO`sgK539i3Wb^1p;E*V^A0d`jFLLgB5#%{B0+F6&OzP-^YW?3Bi{q1 zQ=4Z*s?(Y*TF78ah#12l54tObIXyY*0T?+L9-j0I`{2?or}lb9J*0_n_cn_%t7DCz z;D!W!;6dXZ38+C>XA;eC6q35CtnwfMSHG_`rXgwsZSteH%%othPI7UheY4+M<$8Q|2gPLoKk zZKHT%U?;-_lW%oQjx&z9IOEo$d_=D-Z7a#RtS|)ycJ<2>j{I?)^XXl2sTi0^II$sy z4f9IY$8Oa&faW;V^~Tf5!0dgx^Hqd$Nh3_wj^Y+%wZ1n1$0Hu77pNlxap}tX)tTj! z?9nyMQ6t6*po&7<bp?U|-S9GkF8agu%i06(ual}F5LYef;fD|WtI$ufm+ zmfmFz847YvdB->)dy~{sOuJ)Ev8XXh*f9_ZQQY(#^Z9zyP14zUsV&KoOCLF=T$vq? zI3uqIIrcw|o23!7Ht{=5tb=+Z4YD!s)2QSOamlEPxjd>xJ|&lEfFi~jRDeHt$I$iT z^5(0}a(8hW%7J$IVpAAmIL1dg_p5S806-8+J;Ye@7~lZE#8~?JFMqaxWX499_tk=v#-S0?h}FFT}-BeQvPEIUt)t&1!Z=wxzq3MSJF)VE(*T|ecI%ERrMz-Tt#BGB zY!$ID_456r#C zJbI6<5L?4@Yi>kB8KB(PUUnHIPKv5Al_2s-I3ok7=Rvb^G+uF7GRhS#;s_XH<@rDZ zk>4ETo~EXx^&!iV5yu2eEUaOhI|B`}pDg+SI}y%Le2+>Zjhaa%oCT6jNMH^JU)GqH z6GwL}>USb5M-)3wT29y<`uD4)l0}nZqn8o0+&dlNfH_bzj305>ayiZhNk&J{YEl_3 z;6)}SV0_k)hMOJOax>cl&{f1|DH^)81~B3{;>bfDJZNiIa8DxCNAS`AMI`1EM892c7KDC>SjcL_RvTpR-9MWc=8dX#uwMPd&+ zPq8(4O(D5}2r$_`VMv0ip1IxpK#t?N$El;1%sr$nu~Iag*uiZHV#*tN4f7Q|5OI#9 zjD3A*`z%(n2aaWEqmVKif)T`d&PXS(w>;LS^b*A1WwwL|Xx`wd5;k(({{R8UAI`GM z3%iF6Y~+H4XJ%ca3<(1#Jb*iQq~#vxEloB>=%AzjRSwzb7(YyYHBQ&c zWZv;Nn;W;5tV?1(zfWEV_*2wP9p++LB8m{rGB7(>6W96-RFT}=NY@dix~aE}e1ILw zjBp7Zfv0rP>B*+Y7K(Ti$%SN6>av#sS~bo)dvj4w6t>M0lN`{x$g!kQ10s&VdUP2z zawri}?FmMX2^FIYFkdn}0zo_lU~&gu$J(NdM-0mn7Z(>WA1!6fj9G}_aC!cN-m<9$ zBvZBbG9dXT7NE$IiB}$UoUb|PdW;^GvX<)yn+cM4E=YwHi)Bu8{Q6cYwTbSbgm+2WQyh%b98f!iL@0B{8@4a6!#!gMeGifMlC^EO766ZQp&1MKtjZkjAK8Y zS#Rvr`6FPF6iFV|R`Vp?>P`SW=M`5>+7U~jKw@hog3+WgvSKHE$jaNYM?D88f%K^o zTgF+E=gWI|cPwifD#%N5)D7JSu0J|reD_jKG=f#P+R@osN93~s$5Fu~cRy27$2Qpk z0ZVS-WG#W7zWfT&HDYILJqnW+hFF*r5+Z;Cj3`>Pk|ISl!AH1NPu=btM(1E1$n%W$(51*TO}-crVl zRU7-iOrHMcwNOr()2wb;ZW(}*TV~uDv&x3(!1T!Lo;w;9nV+z;Esf0)Mu?;;RhgB* zSuotEbHK)P*!tFO+;Oz|w1zm5Lo89R{IlnvJn_Kdty=k#-0zZKvyjKljU1Ts?f(GR zrpd8Z<)iu08byGWJhA5|xft!5Z6wX0lzNsRbT=yuo5YJ7KbxG1822QOpj6Fm7>E?w z<{8w^T1+wP!j9ne&#?8P##@WDic=ay$O@wE%Q3;uPhWq=ionU#JfiF8jyWM;J)TdP$^1k&1Oj;;o~Ny7$bWcIQZ+@k z3kx!qRg<2$?bD9GopZ{QxJq$It1M-%KuKfH(%5_e$_G60&ObhtBPp6F7x!#as3h(& zk~b=x9&yeOr>#($*6L(SsNj+lB+R?zA!BJ20C4@rFnQ^b?OImsBW=!sPn5<*g@Zz} zcM8PihddhAF=(nhtuDniNFAk-)-`lR3epU6IZ{FNt1-be(ZiYLhES>Jm@ur$I)F$a zcXa9evrt7k-AZIQG3-0Y!2y-I9`zx(W|n((MpGrgZR$#mho(F9?^Dd~b;>qRQrnqe zj%dmcIwGLt^2a>j_v61xu&sGBF!Hai8P{~?GNo02zToqY+<$mgOPQsPToqDEsln^D zx*x=HDK0;9@LUq}E*mj63aG~fV;qCeJ^uhI)jOQuOxY4xA}sGxPO=vk}$n- z>Q~#;QfzCGl9JO(U8K5}W;>aWQghGXYIAK2jFP+vp3_s}b*Ia z%rQtp%kvOd*Pgv9l5U1!0_9VmGFQRgdTu0fn%Q2)sl}QIu}}6>50@06HwX^ZB=P~y zNcz<|RW0Y8rFdf(7Xx<1I|}smCyGfP*<9L0^19`fB{BJDVd;<3t*czTZ7=%Z zR4HGXhx1?F7;)Ni0@dA(M5*(w2{&j6(B~ z?NCb_Pc%}-hDe~9a*=IW8A0Vi!2pmtkZVd^(==!!g501~i2>Xlv-g}8#zt|0#y+(5 zFsoIhCL(xboXCX^6;Qw4+s72iludaQF%ni3ReQLI3RgU?I^=XbW1cDRW{T6>5p6xt zE09}hQR*@I{uLB)%jAL5Zzx zp(ClsPAMc7%N&zj%EI<(ml3*Tf3+b!bH`!a`c$^@?n&-$9&|@_5iO;@=?nBbbA(>NcH#(iq-+;;ZXZx9M*mPP*n zR^gjy$jRq}$MUR>ryq4$6xtx_mTuB{OckEu9LC#Mup<~Jrh58!sTMewbdoHt(}waM zLL22Bx%~2dY8GhH@zo|`AxPQb0Pkfd^YtHvJquhEhS``bQ~meL6(k>**mt9t=%@Sml;E8|>(@Y@MZVzVbg=6po5nRKsao1^Bz8+R$-a`((v2FEmB8RStDb)fjRG-9&yL@H6_!q-yhE2 zO~`XG92UlL?kbuz?>vv?tdN-%rHPn@Amnj_o;uUDk*~9pTb96@E0>Nfld8CA?jj_O z+5TYgewC?tEVr+5aeFIGD3ASY&*m|1bICdPu6j$+14J1nQ6p_sjxEca@OT7_dY(D< zspi~?KIufLcICUXW4}rlH&SClPDs(UxLKn=WU)4uuuUFq7E+~#K4J;ZSE(7#QIp=I zNqpEY-RFeLCmRmXxL&{k*8p;Ta(mWSohktYQW$Pe%M@*uG8O=kzux(IIODIOt(e3R z*hwA22&Guc-Qb2*IqZEq=BU@%s4^LR$)&e=6v)oFW*EUg^)SKA0~Ic?d={Y5qjZSB0fm%C=UjYBP* zwy4(SdX{3xIT*&=V1_yASIv#=)@!PkvKAJuRUwB{h8cq%gu}agDCA@eax;n)QhJ;+ zO*1y`Gjn#LMo%K;gIqj>mIV5Y5=Zz|o2z@fbz93g#H(O{tU?{iBPXk8j1oY>~vXj#yZb*vSF&)1SNfRHEYMXD@4MrrFwOHZm>4w2zK(@vtCw;2wjeGsucpNMk7l zlDOGoTlXq(afRUV)2XSVidbR~6wKkDY}WE)YOh1I^*nR<))J(yQ*kRiaktq~{{Yqg z@uoZT^JnqnuhaP~fvx9J98EA#yG8*F=bQ}p7$4+SlNpX%iKB^RuwAOfqzfmg+NVB; zBxe{NwG1<~(FY2~2XEX+$U=-{65YWAu^zOPQbtyNi*VdsPa|B;*0Ds+RyNy!!_WbM z8;{WX(1{pw-g~3I=JF8ytr+Ap6VQ%81Ju){k?pNg6B$_K-Q+2Vm1Z4&Y-2owkF8aX z<5;D!I0iy(mSo?z^Qs8YrgN1d%Wdz!E?_byJVf){?u$!!UA-9xfzctVjod z00Z2ddV10;zuCp3+B9;;!bNFe0!%RO-Aa%F8RL>iQchTg=`Q7-StNK_iH!;$!Hi=Hf_gNdEvxRL_=uG6&c7KJ>_BNG>f|3p8^H7AS~080q=vf&LVwLQYx{N|S8_ zlSy#%yi5e%LisAu<0GDS?zy$8cB6icQZLT}Rf(hgEK6z24x?BWvAuL-s z1dQOGIOsZdtrd()Ug>2MNe#nEG>svVOJwfJ=e|cZ-nKY(xtR#Kg~(f&LOE5FaSSj$ z`yK$}pU#(PogFtUXCYlB&nMdgtzBBh8mrw|mMI##EXu7LI6IZFLF9EF^pM>twSr0E z+jHhKe8Bw6&u`Y9^frsSM1ldaVFPrnAMc4hPx%z+UQZ?h<79}eA~^*4XM!`&dZu(?sp?3jAH-}FnZ^UHtz|y zad56>^GC|RD*1f%J&5D=^r>AUyoE|hV+FmP!lc-deCvS0zEt_LK*mb|K%h6kj8l^N%zVMMo>9t1 zI`T@W2aNX4PajWekr5-rvX$P7NIgNp{{ZXNh}LMV=JKUz?WYMOiU})>;1W9=k~!y} zdWR;>CnYQBHfUuN3FeY*t!e{?R$#=Q8))O6X< zDn<;gy=9R3h(C8G(17;G8T?7_?N$cUc(F`?7~v{f0va~YxXwuWz<2-(C)O|((4 z8}J#3>4BVc&w9|dcx`QBbdKL*f~GROD90Rej8<-vv8_2?%EfD~{%S=B?-mJv(d00Q z!zk&HGBb|7a%r$!PZU#bu!7;)B#+9vyOV1d&&`lQQl#()91M(Ro9C-3l_UiaZq9JH z2cCU#SFPqp7qVTT-jYVv_PlTi$i{i#^ONh=h)0y`_c>ODTUHj%EuyuH0?}h=N8euEv?ke9mJD8vaZkcSKA>{J03Qi@sXT$8Ks$;CMIGNB$;x+vbU~A zLG4d6LRNULuA^(4fUG3EVrP?{NWjKVQ=ETF-YzJ{RHYU+RGBR;U{wYXxJKZ!0o1V_ z{{WpaRNJzwjKLj-K?IY*7`Li0ibu#E6?!QhS$v8d4=8I^punpX<3 zB&4oaJRS#e$j4gH#!`|OP@Ky$z?ey+QG)Q5hYR052?rc^s*+pCu$fGI<14tHy!zFr zmM3{*XO1%&`9S_9&M*k$vHYqgb{m`rc(!4p2Wf745B|MjI!fYBdUufH8X#;se)6meP^mvgeOohIONKd1iy zs!?yqg5`qmSeJB!2FK%^Vy%G`$Ymv+9$Z9PB9d+H21f_loS!J8?+t0<^W3RE zQ?qW5JRd{&RmEp}c2!pjBvuWKGcTqOV~UJeq$pN)j%6owQz{U-#y~mlI(q!vjAGQQrma7PpgY$H~VIMz7gjyrsi zy?{}`{{TLfTV>7Us<7Lcrju&Mu%_&`I0GF?{&gct=GtH-VIh@5GpS$?PDj`L@m%#L z`OdVh)O@pfL4S7yw-cInESwk;&=l>shw@=73EkQjruV%nAh8zW%A>c{nhJ%?Vfq2Dm}!ZzRIyi!H<~7u+P6k{uOdksSUL~ zD9uU*)qzF2v^ObxxH8Elw1BEGCj%gzzyZk}`&5?DIz}!FtVQF?0;Cr#o2YoT^^M zNuj)rgKn40f!S0_=OJ6><2{KvIJ<#&V=(K-$CGr5BN`TMRc#aMw@fOSf}v zbJ*t@BRJ!aN_E7rHN~l7&2F1j_m3_^82%zT3Qx9iT~UK*+MJqb(6E_^cQI+w$qMd{ z-%^;z8DbAc1RcZg4^p`AP|B{3ch4F~P_o*`BL(`C#~Jmk?eB195X{5Oa?r_bY_b_K zlB>0{4n_e!sd_VMhfxyW9;#)Y#CH{J-NvJeQH}+*ofZgfJO|;?ao^`$EZAa zrp$~dib?KTHB7W2+j7WBKOh}J029v`t4NSsLvbX8yiDKd{zTzcIWx|9B!Dt7FmsN0 z#Z+Z>WRhr!o@MhMGGR;4lHn5!pmUrbr}d#;IV74GV`POPQ1IjyWnSR%jGli_dX47> z;!m~QY4EJE#+LT!wOBFF&470>!u7{v)S8w99D-S;wp(!l5=N-Sa=wE(GDXbO6|r7KTb#ISIClUbc1V03~m(0;3~5Yjo+s@`kJo{@w|J2#Jgnk z8*32JsTczug!A}&nyhD%C>|d(dj{OBROLsYJc1AT_r*$miKk}tEJ-WCX19thr~^1%r|c(yzxe08Jq1p)udzd zg1~4FBl5WK_O4K z(yUrLT-rwys)%Qeq=onlNj&8B?Z7=h8o4BP!Q@!&$c9x@bv*lBTb@Fm#9$obq3g-4 zwRN_5)gR0ekRe^cmmPh7m1?ahoc{ZgFElnVY3$%jJkmH@Qj!HBk0hMroDBTDcIUNI zxKt8iAp35v1aU%e%y`f1%{jb}AcmQoPnIal_gI|q=zf)I)(?kGs!t z&NIz2FEa86w27jR%7L(Uj4}4^KMH&aBrF}6A@Yx!n|iO^BhV9`{dx7Ni%w@eVA~mO z3McPpxQ&{57&H$2=N)rgcaFR=d`IBzb4!{p_104qGT`GJ{{SJt`h6?ESnXj2P1J5B zV!}KIWaFvG@9kOFkx0>_NhFUMX7g97^}zh|o@+%_Q<^&|&B9ktQ~9y@li^9cJF9q# z(pwj`4XZN?c`~wjYr>oijjRqwvF*~lPvS&cjNS>cw$N93z0cY$<|U)xC)RtwP9uM;{=cnMgi^*V_tdUdkJoCpzz;^A6ZR4 zO)wZOuXUfcvr4Bd7b-ReVn{*A9Ax!8n2bNOiS$@!Dw0hwveZAabh%dAOA{%H-Zz3) zETOwHk>k2e;QA!SL??07JCVTTp^KcqY{knLYKYhmuE58Cdk|#t$H1k6Q4UE}KoW zZ43w#X@zc<_Q9Ee1QW5y$9}4N5ni)j58^5J{CB33* zx0-xueR&PuqdaRfMk7^bQGj|9a1?X@0P8*tYEf6bPgfNRn5uA5t;&~`?tKT~y%$lo zHa0fNc?6HA2RF0c4=!!Qjj;j9V7#*&1D-QWs7t76x{i>RntrQ)KC9w)wz;{mo*Zem z>ltsfOdRfXW*b0F&$)psv=TF{v>y{`+WNt3t(hj%?IDpNwS+M?$038UIbLuG1D<*5 zn^2~+rRo=2%vUbfvdR9N1j-mIW1{rio(_JarF=eVfmLtHeD)%oU3V{O8GZ-7X;&IV zULCrqG=>;#Itkr zXB~j#d*Zx~)5X3cO+Qo98Z@@BcvkA_8=KJ^?s1eU6LTQ%xO4=6cvlwwA-j`FyVK#+ zrL&SPlYnI$d)1Jw@&eQ{F2-@1{wZ z1%@%xfHFODdFHy$3ixvKRG!mY({)RWQUTqzOvVUPxODrc*R68?81UAmsM}s^7xxL6 zBSS1M;bf8**+>jvep;rE*5Z0KGhk=Bm%9Rdj36phSy5dtaL$k!W&!i;iX6?5)Gto7;cT6 zf)8*;E7x=n23d~*&EjZvdvrIqEgTjx{_%?@3liI~tO;B%UgVB5_ZclJ)p1ewQIxv; zR{c+x%(3`5Q}~o`YvaF%KM!?_e}@-dHqpK!-r6VF zW;gm3w2r=Wpx_c)88{t?=bm$3r=cGjctgN?cDJVZxfa^_6>fC9dx-8Nj$_M^TX65# zXVw99y=jxM!2GKE*lpEasCUX-VI;N9u>MkwgQoc(2oRWX7csaIRfW&i3G^=whb&b-y-OID}Jw;l* z97Bq$OIFsGTU$iDj!WTB#Mvz*)9tkjYq%_3mttMco^zl$Ex2S2-9~z3XOUlbXd1Pq zqh^!BUt_<@G6`O!6OV4=+P^3-Z>_EMYinp+j4LY$!P=@i@-jaT`1Y@(J_~$Ty3=Hn zLe%d9S!Z-;#1pt5Q_eQ$f$BX?b@0a+VzTUN!{R;-uWgT?&T^Vqn7XvrynWmDm6>Hx zCg&(reB>UVhc!b?x{?_qj#e=VyX|2jlE{7{FhOI1b7R-br%0=ADdBG#5GwJWg6)S0x zLd^R?iPeVBlxEl4Ps*2UAP{nMR$ zqM~6ujf-~O1-rKl+33By^{UrS46!Oj3%2EAEwhG@a7%x*I&tVdD@f^<$!i+j#IiIF zzCe&=m(v}=2a!;`Yi{#LF>qVjEU75*yOh6gsLH3tgX&T z_9Ki|Tx~KKmLDX`yciwRaw`u}j4o(?(;@K0{FNL))S zut^jmIAdk=V?`xXxAmtQi5vT6ZAcY1I|q(T$tTYY49eN|1DdZZMKo6vMI3gZ%0zI+ z#D!e)21z^-j!j;$Pcm&db|KkAF*)n+n$~rrV~(|W zz)j6=iFGHEBapC3rQ-|-E9iYrf30v@&aHD6r6g)XtZgE>fri!$2Q=AfbEcVVnzW6sQqYtN$qZ}W}JMdZpT~|7~`CA&t7Yp z07C;at7FOx*kORZ>tg!YEwmQ+F0ut-v>am@ABgE*RV-ae*!bF+tmQ8wv^Q4zg{(nC zsd?LTFj85&^UnvUt_M-nEiErv*UVYqiQ8hdnLCdMp1B9NYTMD=Lu`s#Nxa+`*#QJe z&jw(WBrhPx3Ru*vXa>>S#10((e&Ogbn z&rgzPiParhV{+wzB&a8!^Y3286{w+EMxxj8I&13~JdKJ%MqGw{#04DZ>-blhvq=Ti z@H7n^5yaBQLx*`A0ALZVHV^t-~zmsAayOtJ$lyN`r9co85uS@ z`6(0y%VmJa$_@uPB;WuKAmX`=JWB$rTr#!HuIghE;Z&2R}d<1!6JU5>a z8jOjR8raQ@|ruKkutEr%42h5 z2fjHRWCK@E5w7Odamr6~3VXYG8zCzigO795@!-~`jbZkPBQaz-V9s53 zmRx7p{{Z^yoz$)k#BJuZad}K+2(ghOs5vEx1Z`jl0Cd6Wn)ICv+QA68mcr)fx-5|k zb`j*C;(YZOJrAg_N;RRSndK_*l;6B|u}1cqY={loq>8)M6qw|0MhP9pd-|Hpv9vQg zDu9MWD(uaLj1Rk&{-UOrQ<_#-R#uMMUA|;WzO^#R6_v;Zl*tYWxr-t;R?c?= z&&oI>ryO=QoY(TjeJ#XNEE3LRS>{FBsRjy?*c~?Td!Bu1@%^m35V={TV9~HUqaB={ zg+w%>u0s{Ul2=u>f>jUBe7M0plhl>L$FJ6cAe1nTf&frP27h?O z`V9X7L5hkiJA0jw&E~4Z9_$H71dh4J0UpQtR($b!4KqPA2xDx-z>weMjw`Y>ZjsjW zNX97BytWyZIGsU`Hr(5Z`M=MlarbiGJh0o(8m+t|5h*NooagZ8Cbbh<@}!PmE-`Wx zdCm!8oc9NV>F-j^%XclpLlUuQ(XGJ2c5L(bfA#947Z!Q-tE%sFoxHGU*D&0ZEQLp@ zUTc)ppKHh@FD#|LRRpkR>`$e2S62-c^p_GxBHGB?au3YJ^%>`_Qd?VdDKasYWyj7G zjib}oBRDna!dFLujBlIW+|5lrwnkD(k%T=ul^wwLJn`;o)|qQ<9H3kzgiasJ-5?CD z{{Yt&qa#|0^AgDv&ZSIMcnY{=&j9HWZX0W@F|aV*{}EKBlNy>JO=1&atY+B)geOAwV3H&-Cj=(Ob$M z;K>B>q^CP)SC4Y_xS&{k)w48~Vl=xkZR z7EHGjv1~5b*k@=R0LbGfsq4*Ky+dmxky|_^WITCnuCcK6Dsap6KhChO?;!G-KG3cZ zhAfBX3!Vpl*aop>*TzhNqq?_>4bnZo%A>a@j+_Eddh_QAsU1%+*y)z-Zf$O(fe)J4 z!IlyUZk%LRY}!SeByB7(o0x%BynpqIr>Nr?2dVlGO2xOTxZscxi+rGi}E}c^sT`T;8=Uyh^aF(M@3N#wa0= zYb=AN;(qo!dUKAoZhJe$46C^TV0ZHem&u-$fFZ7$4qgbvM7)(*}A(+S(LVAY4 z+&XiP{`Juv64dpu+|hfSq{4Wof&mlch~`Xm^3Hfafd}y(wR+x5#e9cI7)m^$pPK;p zCysx{v|hsI(l?GM)r5?5DS#H+!NQZ0yyN+IsD__=FPLSv^8A%%%8=e-a| zo8~@;4PTbUwVpT(w=&F&GzFStxU({jp4rc*rCPP|0vOTbDFR9lGJK%tILJ7xXtZmW zZ#GdNv?;PhiYAe_6T#XtPao&0uCmKRhSBYOt@4;rg3U4pW?bb7PE}8?58=gl_^LE9ex$PuQQgD_=**`eM@b__Ysaxyw}9D35*LoLM5 zBZN7S?+!9Sr@s>h6NTw{XV^PW%Ays0Zo%=(H>GKacI%Or71tQtXa zGfg^qyMmS{JfG6CVUdzZ)faR_Cgg3;131Ui`c}2ot@5kg{{W;QniZ8`AO%=Y0Q!ua z5uUrgf~u{QpS*XBZI&|0GTj23v(Vt4diD0Jyjn)fVz-$K39%oT46Ef_Nx7LYPC)0} zaqKB2nVBTSr}vZYAPj9>4xD=K{LNf=UKsqX#zS#F1ZaUm@r)rH=b_2Zdd-zuDaYE3 zd*_Lo+zA5~#|L&k>tqvy&MBC;^e7a;kh~O`P3yP3FM&}{p4)w!Iha# z4@h66Dww+kFmF*{U`?)Lmgy;@jc^Wufgw3A0GBB}z+Tb@U6`{uf-MlQnTln5h^ zWx80IfHw=zAwrCH$-F0FGQ@ zP@gVy&Unui&n|w4L=%!4U@<93Aj-$UMUXcihhlSpJ*l5(h+xTQBHP60_f`@J%Jtz} zkUt#utFLtIlQ>x0_hKb%fCBUX0PFt%_0@RRXrKVZ?G!Qyzj&l7umd4ad~kU6#Y`OU zsg&s_CP4-wu)K}#=4nl@c%=)Mm0hKYkCqM#AO5{bJ-ywt1eV@gc*-NBa;qtI!NKRK zAn-@^sXWOg+*$~e%iP9iAxKfl9G}zjtYyv2MERgg1-wpWEhB`tg>bRBA2Gq_Bex?S z^w}hUTPl|(QtjtV>)NC!`dE}B6B+BTl%b2m9$3H@Tl@JFc z!h{6_=6J&@^TEfaYWbHbqH=6|$YG5mEYcEksu1lb*F7^)s*R5p;7KaOXFYj2{CKHd zW_c0hmDtH5x9=PhNF3vj$C?Bt-c}{IJehAyk52uonxvz1My`=q$np7UFmF0pHn)`_ zR&J*`>JB@PtvkvX*&C2PW?i!uVA&%Fl79p3S{G3^Jk(OHwM#hR#6T|5d*OD!phn57tK}9#(sZMl0Q0+C*#>iPKIeLZfku<--$PG?9e~x)}Eih`{GL z#xahDlgiD(e2*=m49+9_%z9w^59Tm<HD=4nNns30F@mK+1_1U0 z^ymC5mdzI$5xdl@EYr&ZMJ&XKLo6Z4$Ok8nZuGFi9YlbrF{jL@Jd^lR-COzIa+&kI zHpWIFvz~B%l)@O0tWYe^jers5udj2DrcWP@QkycBH5a)uTU2}}d)innYbmg3$&`DHfdIbx-N;Ac3&`qQRTet8*!eW1q% z+!Z(+^V5uup0#QYRw6b<4WYhvE4M4LIuVRwr)ZvXC6@aWJLQawTXTI!QA~J>DQSLK zg8a|;{{Z#sMYnm zc0v;4cbDcUUBn*Whd+-s4aCnR_QD8ONo0k5*;(*ahdXi5f;#6NDbWEY`OegDyA(1I zLhq;(Z>YQU5j|5 zWb-4J%aI`@?o?r&p|VbT@=YMSwu&~6)EkK4;#gn9Y3vb6|z#f%n%$;rS zBv}?aQ*PP72Mf^T{+!nFO(CMQ$gCM=dWD#!DF;1E?=RCLY&@7|?bm6W5QFgDT!xVDOCm&#S0F7CH3 z;67rw3xS-FIqV7VNPp3M%ZV+l<{)q~dwOHmwd9e*g)s&mR_BP|@JRso!OyKJH)E2uDN05p(x_swGsr+m~=^j~{)owRNkgQQGdsRjd;X&N#O z%N?aSAZHwpT5`r#8KasqT*#ssjDRUo_lfsCfb00vN|3mX+DMuI0C&AeU=Ksz2im$* zOxK!BY`-CAiKC71zGbA_i!zhc91+u=ahz3KhIve8J6Q7$6f7jJ?s}hbp4c1;wJRHt znL(1jz4m4F_378%qZcuV5=EXRhtE|-mDOZsIpb+L?0?CrmZF0zC<`?Zhd-YoT~YnNqor!Z=6F3W>8KPkTP+SGEYuV zO0>`msEm?fe5EZjZp&^5fC21#n&;+LDN?Z|yhTiG3P>bFm40@PamVXbrdd&=l|p%J zt+Y7+k~;JKD&#jY!jiPxQbDzCxC%=g=O?(^+N;76Ic1QC^6<)smR2Nl-?o2RSBa&X zGuGuFeZ#DP7{a#qDh3HT=luRvdKvE{g_=obXc2#Okv`SI>ZA4a>-DK)ONorDYV$p; ztXXU$kSaTj?KmU?z+?`4nvxU|$jcy%<`(%J0t0j(jZ(7>Sj2)!3dkk3h({jS6DfEjVpdBwuQ|d7OUn=eTXm%t!Hh=hBiv5eTU?q`?aksskeA z@yAimeB+ZzSu)_Jn3w+mx_Gvvkj9Ep+%EFZ{q8-;KEVDo(x?L}Tr8{=PtBaMJx@=m z{{Z#Ur0$|A1Z?Q;Kp>1ZI`Vj?O#^Rj4C;3y=H;CdvxWCQ2X=ViV8OLsz{Hehl#Ttb7cnn>|K9 z#)Nny4HT^LDuR62S%)0<$R4#D zB%6vWw8~>A%##F=J$nP~OB~L!?6-wg7cC{ro?1*`agK65eFv`+EWT&j9fGieaHn=u z62puRGmpe(w~XH@$y#kPC}3jII8}TRi1vf}f1lQ!wOUCg;8Q|7*qE()0uFFnULA8<+RYPZ-s2Im2WBe-XMy`dSStM0o+@i53 zoc=Vee;|m9xQZm9Q3Q6NvYv^R7$cl+C)AVPqU_!=ZRl4qz07jNjXZNSDyY#$8Hmns zpzsMfABn5>u$S1TMTwNGW=n{PjAVW01Cl*)?^Ryn-U&<_q-)U1V?~6R+CSqv#z0}l z7r#7=Riij)l#q5Y;pK3GHT7Z1BN^axl0E3^IYv?3rE%p=bduV|6h;?2V1_g0#&N(3 zPD+n*ezj~&(WIM@2*a<-oPvF7rd_#5~>D5$pu+ zaytXgbH!~IVrI=Mg}Ig1;bRggXGj`GEO=0ZBPvN5Zr_2YO2L14(kv0Gjpgt*{Y^~A z%TpPXCCADL$tno%{vN*d43O?K$td$9mQ_?$Tn)pV^Vf`4uAzlbQaihOB#9PDRb!EU zXM%FFDg(ndFjwjitt?A1xG@RLB}rU)p_R|5#(Q&CEp8z$23RR(S3?myfaC9UQ<{_k z6~oB{=<6h5a)4t!#~>Vo!Tf1+kl`-E%J2m9<@;2Z5(H7F+D4^hW7Gy>2sz+!&Uxw0 zW|LrBbcy15ZUPm$8=5sIB$5H??Nu(|g^Gz^AJB2O|W zd1CUXVu>ypqgEZgeqQv~k>U{ffR~X7A$e79`Tqbt>QihYj!ES{d?H+dDZpQGj^nL0 ze8vhKG~47DX303sXR)Ltq{w9<<4`s`2IFQJgPeBsIjPXJ9%2c8bjD8XoF3oL^QPXz z_E(+NcSjSlY=~|}Vtsn?^{Aw|mg3qd)orcP5X|b9;K?I%$$aM>IOshxO)YP+q+;$* z4ibMlO{E%8(T%5Sk56&ett@^~adHSo1pK=}Rsirw?lJ34JLB2EZXP~C$Q*mrZ!D2a zjpPPx>a7Tq%U!)e93SDq&O7_oZMKaPv21LF6-fR?{{T}K2R}-zs#r}c?ZKA{V`5jh z109Gt&05@dCV$o_%O_lCHC<=7k!2rfxB&!#AcEU^$ocNvZO5*AoYGpFds*9YrZHk$3sn!L?&Vx z86!x+D%d7Q1dIcManO;#IQ1ETg^uxt;U4$>=Fz!Fr}$=;Sfq+%ed=WrZBV#n&-E3o z9nr@pE@8Im8cbsf9gsF;DhU9b?a$ZxRo#(XL2=|p(V0r93ITH`LyQdbjz9XlP_5Zb#hK(P7da%19!MO4(3;v)Rw;84 z!ixjP0d*IbC|24A$&zV5x}L3!oE&fsT`qzP*<@>2nFMTNdyrhNaCjLb@$~Cc$7uxn z9&aU7Wvpc{nF{*4@?$yddjNaZWbTs7I+Gf-F*I*7r~_xNc=YOP8`+hhJBb00sz94y zMFmQ!IUpZSohsVy!IWT(m`xeL*&FG%x7zt0TeEH z3z5&$+uEb^E+c8IRqdZpd8b>-&eo#l)gzm86Esr^6<5=->OWCN%srw{ zVpohh+z}q+SlcnjfX)x_jN=FDe;TkHvY#Baq?Up=pd~af5hP88`t+#&CH&bo?q=C6+5#B=Vce$P!7k<&H*w z9%{Y4!FXYi!hg~TWt`?S3g`HN>_-^j=O04xFloTVk`eO!&z?a%ghqj}Aw7cxqW78!1ERdPUoknqFr1#fJQO-;H*H*tvK zmL%KuX&r*d!=9rhK|FE#)cawA1RhLH^0wrS0s`P*l14H|9epTrNK)iwAt*^gEQ%gT znYV)3Y;aT%2=C5)IPXw~luRueJd~wA@uv?auin3ffgh>g?sO0+nI)8;eRP$}bY!zhkS294wTO<5&+t!kI zF_dExsg71{{(qE4<&4G(5ym;{4;)l0s7n%}S!$`n!)DM*BAFW)JnNdrI zAqz5ymzE>9zI`f!UBn`h?a;$2DDu|k0*80|r>$)inlo<5vXiMyY?e9PGZIvVZn*qK zD0d}`EFci37E6I65&T<*2Gfv!Q|;?d`$EW&qaEH-VF@IFq>=#fKn}k^^yeq>KJ^4~ z@3y&lm2H?df2CyBqm5aCm~1I1a6Zn(7$Mxfc>HrswGq19O0w>Aow3Oq zD;CB;83Q@>2Ng8%%CSYUqnbhGqcSk^`v&B2a5MGCzG^b57n;f$yr}>|k(S6L<2|Xy zoMg_J$+UzeShR|d9Ic)HWP=ZZjy*kj^{FkESyTs+G7*bLSye~}IRx@Z#yIPqhLBE} zR)K;`42sM4m^{TS2t2C{Fyk0J9Mu{8-#QjaZB=s18@it`jOCSmJ#p>$(CFBwCSNOo zB!!4!%WdpCW~%vyINcd`#UzWly9UlGQEe^am5M>UD;8&zDwSWD_28Umj->E8s3hV^ zA@f|q$gLh!?IlUU$FDuA9*D-HV!iF9ysvKNbG^2}Ev?Lo$Bqf@`2PS(auhIvAd#&I zZN*ttVI6YW=N-82N2Ng%vl5aOMY?j{OE8QK1MAK}&Iew2>rXdJ2?^!Mt2^OA#yaD- zt}|IXv}G3giwakBAlk_+t>s9$B(JICgPe>E)2-&;E6KEdnB*jzc~<=oUOlQNh0YmC z3eCm_4(|NZ{JVEVx1Y{v+aGEXNMdcdAcZ54NblRyk7vqlCeY#{cqVJNR3MDUZ!y~! z9EENPT<4y&%ZSvwGVkaYhHsc;^VhG^rf6+fbTJ$T!!G{-nSz7Heg6Q$tVwYcgr}A_ z1}bN5!JocPNgeUWr`EPx0<@Wt1O_$?>nHDSLqC}NlmIX>?Z@j@V`#v--101l0~q5# zK~tXR=s#K~xh=H^G6eb8X!$@mAD^ueT?SbqeX+do6_zy_e=m{kTno1W! zz<$#M#!Ey(w%L_Gi`@M&#VT!tn4?20ZadlXPB3!W_0K^~fFjy6waSMsL&Jg#5x`@C zgOT5_TCXCkzr0D6nNTW~JBE4dSx(%ykR$PF^v zsZhQ4V2lo=asCxv>M3Qqh`}T<+Z=8e49?8G58WRr-P@i%pwczGaRV*WEJi0?;yFx< zo^g)k4_tatP1(C5)TeS;Ze?#SU7N`bxd9D;3H*BgKb~roFZQV+kpvOULbwMaV27^c zIV+qVDqK#}#XLoR&*vS%STT}3^!7hm)M>Xch{6?2@@xpBDly#k$DsH3rBV{T>}&6` zxRVS<31-el;&YC_hqYtf`Evw7w-Lyai4?}nBP4p`gV&*}n~)JIAX%dgybjCL=~Be- zypTxca!~JHS8xZ@o^e^DIih&>NhCqeV|ZI}7%UqfDD?WD=bC}{I!OfHK!B6A-V-1M zcOY_bM^DO-NgD9QaAYJgZKVA_3Z8d}4>$yQw)~8s6Sd}*@=g{@_=B!BEEQ(R0$RUT!#c}>MT7Np~ zDO%kPo9+T7xhlm^soU7~{Ao%&teIXUlBx%aMs$keI2tvQPi|%$OGH?pFdbyCJr>-Mc&{RCCh-o9azX3^7RV&?FJ53{z;qRsQPxeNJkW zZp(#9E9xMLj9re$70j})`Z`=YFYgal zByw;$1Jn%U8fH>=WRWGc)vTUmNeqn-%`~wRLWUcZ5DpJR&N^0nZKg{+>2D>|sAJ{* zw#>rH*y8~6j`{bg(BHs?QfVYziql7K=V@O1vH{3EdSsrwR6s4u%{qB(V`JgKFhbQ#n;Vf30qk>~_+c zRw+d%?_TOf1y|?TP%`HnWFFlq3{YFzvA2Oz8;50<+ybkTN#N%{ksVD+W{S*8Cqc3P zQ6|tfs2KWtpT?wjF7R1GyW&VA**t1bnISpoILPV11EnQ6yJ~AvT*;LTnrWS4cM;Ce z5G~`E=2bm_CphD;x3x_pv~EC`b-6{$$C9c&{SRV$)QcoZ3c9p%s>)3AfCZI%#`spKdel73$29Zm%f38T(%yoS#r-5IhVn%SrvT3yn+DZcgvs5 z^{SFzTt|848*?F%nWTiOvoYLH-pivc(cBNh$vTNnb7~MmClT ze(xQ4CqLm$OPOR{+wej9iwzipMpX^d83*PW_4f3nP2NJRghqBV%Ir4??8g_qmVO*jkpX{{K0`7 z8bz_YyhoWtQBCBo1hRQ!%U`YrPoU({4O-XpJ7p{N79u0Gg&sY{+iqCyV<%t8^`_rj z$gsyO5pTE?MxZNgC5b12+;D$NSr$(&WLGhmXJR%0Tg%7#!;nWgBZ|2mQY1!cF%oX` z3zAC{lh>X)eKF}>7g6eS{4(6BJ&CxL!}*ilPEN_1OajF7xE{Ib^{86f`6Tjfl|e$w zxZD+0U-obh`$vwytzTrCW`8k7xMLx=b0ElGeGeJ*JoKj9I@zzt%XG07^Mqx#s_p>i z)2=9#d6A=&w&GgDJX0`fLgW=xo8{cgmLwCw%I5%cpMEN~B4wOpqi+ zN!=ja8JWGuU&k1y1%foS+F;Y;k(xgSFsO(iz!y zOuIyCKLek~^{AzWcaX>A38kEf;f+biT=IDD+*PRA;L=YfHdllan2 zEtRaUE#bPig~3_H_43TiCO&rDsxS%30Azqb$;ED=D;O!*uXPezh+0%sOLf_CG}#Le z{WM}Sc8(55YUF@*;mIL{-$zg!x(7^GZk*w3>4%QW()8q`RyJ7HMH+!YKBItXwSdXM8H*xg-pQ9lyz`m0I#9T|(*Erw8q~cT$+j zs05#wW9y!|tlX0iXs@{AEwCPa)YCJ@g=h0-0vMDG@sWT!oaetZ_?pmLUpZx1ZP{6- zgo43;gDao9Sb$r$e*+*B+cZ?##LC-=kMPsxPi7uU^hwXAM z*JMDYf#;wA0iMHwNL@`K3M$0q*e)<3srMcZ@9RS zc}o%Ai+sm?~=Ml;Sh^s4)(wg<>DDz4QsO%Y~1tm7Gw zIOsFU;|fatVB)IWE@TLhJV*iC1UMma*kttj)y2$F78n@=i5N34Jd$gsF6iuq2+3WP zQQ(>G;&X0`8ip44Ddq+_7yuAPM<*tuXnxG#+q_|u_kh(5N`9VDJPw``~HHx#`Lv-zPDtFzIgmS zNdA>Q+-~u$z4TU%D#e+kvbro}{{Vq>2OMO253NLI=F5xa>LcAni06eOnpq?TRTY>4 z)1evs`TXkz@0xX6b-je$w57$AMS~T|!6O~AK*9B^QCUu9WmgFf6tN^Q{{SQU)zp=e zIqaM4?`9)hJT{?Z=dbSo-RaY%SF(tzJ$sq67LwtNV&3KS8(W~qp{mz6Efh0-o;+;Y$-EuXDZo7Q+n#@|F{7R4 zD6okoXvdcr`J`__k9w53CWMrqLbUQ(O>S)zT2CXTAwq_Vq}hB1G4}!LCF{e zxb*4W&n}n%3Si-Q!DhE90l7E$2(Au3@ zbQ0A0j_$=a#{9%`U9v|ZK*!=~E~VQ%${kTlF2g2wGUu*2!O!{PrZF^2_NJaq(8<*t zjK}@a>B;BnX{iHqbj2C&7CebLRrVb-&w7fA@dnd(A)4$6nGL1GO)IQoLm5@v21o>u z2;_9nQSVYfE@hDYq1F}=GOSZEU8{`sKE0`zMP#1def>6&ooau!Wj}wsDcTpyP~GbF@i3k>wP|Gb6H+tDZ7?@$Xcjb&Bp=tCx~OV*=hJ0aP4K(%n4U@FBcZ_b{OhtROQ@?gP4gNt zLRJw9lQZR+V}(ZMUc;KFc(&eAh834=2u$8|-eG2AmdkYoPeIUr6)}?dT)gTQFavCk z4B!HJ$zab6p&-mgc<4$f@L|zEvmll1yMZEWt-?lbq!B{{R|GSpd6XcsY$q ztZ2ZX!Rik~_Mnvo;doG)|m~hsESRbnLcg1u*wwn$JaEf(6E|l zUPd=EvhH$8RbHSB}5 z(CuK%q&7Zb+o9m&s68=JM{h0EQb7`vm-(0+HZkk|f5%Q)qe-W>Qat%0SuPz00|E%- z^v~Dd(=|*x+sm>y@}a{sGO^ms2Y+Awy=}^jBPlr%H0CKcqdKz0GJuiuV;SPDMv6R! z`*fEw?Ee5rmg*rMTc7UWAJg)xzC>zm^E^?A(U)QXtj&y%m#+Y0jwzw`{_S9vImB(2 zesZ3^-{D1)HC)WIa<<0eLmFGfh`w#W6)o@Bk7|bA))RAU_W4WMsW8Q+*v3rCy@-Fh zpp$?`akQLrDgkeAbu0@U_Y=o(Rh^|(jH=_FfMe-TmfC1;Bv-n5EZNH1BRLBQ13OTT zK<7TWHG@_+P?Ijld*x(YeV9X#$+#?Rj0xSBJwX^4?ay5CU(GT>^01r_5chCcccj;E(RJ?g}>PZ9-~LK%paWR3$HMmfkMpw31? zl+TlVR-lF)YhHFv^J1h&cf(95-e9rim-_Q8I0Uk+|Szj^nS^xzv(&G4@g#GNoc!gpTof zgpA{82Ou9_ho8cyiW1N>ZY8B)+rPZn@9XJRq#Gp{5UkPJOKi#KHX1V~c>{n!Tnzg+ z;Zj763>Na3o+8pOofw&)7aTRd~=fIDKkIn|YoV+q)gbo(t;wluK+01A>@aXjN{nQlIp>gZk56hEZ$k^+m*H68g`$x|83MF&qL4uzy?Xxup7oH2ebU>Q z_D?GYknJkPPruT&H=AgN=;M>^ATsWp235%i=y*IHzpYWTXk)z-6Ceoe%>GKqHv#gE zt;REee!V!wN~dHIyDVGj*K*nUY_NTr^+MF zX|Q$$P75ywEI0=l>r`aBc;>pDBuN?MRS1eOK|bF8l-BZZ5rmL=Az8P(N&yA4k_aG! z$LK0#nn=mTuBN+5FPXVum7`UR6_Q0P%m>bL034iPa5YEX+(HR}bbKGjquu_|NC>Rb8x0D@`Qmo=@(Q+T2LNbJ-Yy$?KYYw@9S*L#|a{ z$TGt;(iqq5qT1##OMeqNE6CvCcszsKm|1+d7AUto{$O(3vA7J3p4lFs<5P%YkN39u zc-4oQD}oN*fRH!`I3J}#=vYKj<8U&MJnh<5n4T2%BN#b7Gme8NSjI6a&hEtPI?rqe z$>%XXWLu8qBN*cy5A>#7mNI!PtrU$4?Qc%J3X0;|cqKCD0(Or<=sVzgn!hA= zYi$XKrYeXCMC zW8{T*f>e@L@?E0`_m~+T`1Jbv)5M9jWL@#3k%h!d_jvhu>B#Rz!9n(T;- zUR#O8aRgLs@jAx{P`z+{_{LAxrDmSu;@VX!_G^EZc+MA(Z%?i&HAQ0(wYgcLBZ;B; zve`Tw_Z<(?qL@b&y9;kLG=QlxFh9J{JqJR2dSbVXHPGmslncT+QrcOqt}a&MRc!r| zK(ex&je|TL!z<4mnvN)B8MF~QO#}-d3PP1acJt}TJ!-9>kTS;15s`OXNLZCT_WVia zuA)dUBvq8U5G0M6z}ld4qo#6laCy&8wQWiW$<%F>1n6aw-C7uo4g;Z+_mdt@aC)BH zamT)C7V2pu+Nw+~`^MTzkhvd-t1<+-5&#uv$H^fX!uk=#L2T(6xMp=RL>XXdLBQj< z9N->t??*hWYL)s95bhGoJa)GLxodqr)r&|-#s)g$s0?w(;Z}v9TU7fbQCizeD>vET zwlSRgk$STC7_u~*j|o;uct+NDKA47T#S9LaDF#a@1HGJW{2O0m>a zQtU-{C+@A0tz$t9M4>CWnX|@0=zYDt^HGayg7V1i{)(B(#5hr(<(~faIFT-qUgrAF z(IjF1km|*EbpT)!+xgP@u}QalujM?*q3y;%Z1>~t`u=s4AaYJEvIwQ};(J1=AiVwB zm&s-1oG)%qKD>LHq*^xtAdo1Gk1Sk9WH|@FP)2)Isg6QsK2+#W%0_q{yNv$; zoQ$SbNq4WEAXPTa3o4BDV&Bv2UG$$SVv1@-Xjn%p#N?gP{`rf90Y+Pb++=}|Q;=ZIcgLdz(dyM0cPkN^=ZiP9;8p?}rcm9hitI2Gv*D|Ttq~!fb0~!2&wO-}rllRfh z3{p)h#*+ee#0VjnH8kdzckt ziCRDOcrZvq)OE=t2Om!Lo0EvCRZ^C$r7Q|!SCrkPlCv~(mIgNM#~B2B`iiIIi?|mh zB@2+T3u0tx5b$%HbHM|z6`(D|k-}q@JoVk@VMs;%^MUQ2)k=6KwA&ddT4_ebRt%>t z$s}ixJ5ZWuqZJmn8f3O+iQ6SXRox^)JW0`b=R9{E^XXP2w-)g+FvGqhfG`!KEtVTb zL1n<|IOJy;6z{eDo>C$vKQWn8931n&`twW?%NvpkwaUk}%LQVnPJaM!I(i!ES|gTG z*K#|ER^!Qz77K!{GKT>50#Ajn7Go3bZjGSH~OQPZbh zJNwj8vfU9a!bqtKov9(^RFi|jI0W)OzOrIcG-g)=)4RDTd$dhl>ZYC&*Iq$FZFST56yh4!Xh3+so17komD!WLM9 z?*oCIqmz#2x!vT3n^M$`^j7kuTH0YF}hf_jo_GPlqy&_@c* z=E||C@&t_`KR3&s`Qt0}??e=pja@aNQVCw}?d^f`Nk#MCIJ~7N85=?4ka~~lPliQ} zW&2IUainO(&u~Cl8z+wEa098priXl_vD)m+f4xX@RyOqH^v@Zqmk3$Ju&PBQY*<0} zlpeqa&R4Ho{x#W6lA@y`AlDZt$rLVPiwq}b3Z+LmKZRP728tl_U`(ZVqoED8fMp}q zN|1B(s>a@DUGh%0a&bo0(LcbR3Kml21-^>sMB0w~}XNGffZ@N~Dk8NJk)NsrNV@^(tIR zJgqs5+)K2nVt!_CUv{WB$0f{*6mC(sIk}Js_ea|)lZL?OlkHkY7U*E3HuXf3quet? z_NbxzQi&zGnHiUFQUL&+z~h{B&NEC{m2CsOuBxdfW0}Sj1A&ZZuioVM?b4!BK4S<4 zb}L(ua6*B{8O9EK`g_t_T)2<-#S1P}k}{=xlkN}s?MT`x$d)#b=M56Dc*uLla;+SA z=NQ1j@1H@6sXeksYv)>GJPxt>i;i%|qjAU9nR)h2 z$@Ytuw0md<$eo55d-TEo0PEIC#`_snz1X{+H$_R}xf1-pYlRppu^f&@a;Jmt4l*!l zk95kiM)KS|k)guV2opO+VT0Qd8!6Pa>6o0@!SJ{CVcCJ|1%R!LhyJT(H7YK z>-iD+a>*siT}utrqjMRRN~-E8^jBL$4te{eOR#_K(0yP10Ol8?z^*rEUpUWM1 zt7bcamVm?|J60#SgfwFvc<6EI^!20&?vo^VlHwS+SI9Fr^3PvE){9T<^E3I;%=V~} zt;7*c<+FFhWP%sda2$8eF;r#D=GaYQ43Nb40L2t*iM+S!etZMhupR1Q3&iFnWVl6* zPW2~iH{*klPxxkn90h4H3Y~}>2Xtidx~nzBt#unZAw`WrVmQ`#8uig8eFBjh~ZRRDoHxZt(iJ54f#SJWtMeW zf}?ps$pii2gWIp*Dlu%&6vdQH3@%xQ2I5KM=Jf4~klvGTY}Wp7+T&lI#!F>bZOQ%^ z-#esSbCv@KAXYJtFrAred@{nt{KdDHW-%S0z6Yqt#(2;F09u%k*+{cU(_BGu5G`#G zw+xa3aCbIAQacP_^W0TdNf{$2ECh^ILx4*W{{Yti06DA1+3jSt7n*(Dtdd&pdpoiF z%n(RCWDr3Fdt$5ElgZ{r@a`&=mpm(Su)AFUS)_N}O-#U#oa;g1-T*FE?hPrXLKqSr!q;MtH9%9DQgcfz9N z*OtvL)MVsaQ`JFt1k z^r`MONMUx39dbcj@;$lF9@LDbxXZ_eVIT0af#rg@C)|C1twjSBaS4h=MF6y| z_gT5%a!&vbxa(K1bkvr0xM?MYpw7V>hE!483~|jpY@sn3EhM>PuH`Bi#N)SoEd5}oS5DI2x1&`B!e+p^Eq0ugiPNq=+96M4?^ii=z=@6l1N}_<;0OT%tF#Fy7dg| z*aQ=iv>f%%PGyHpNbU#OrD-IYwxo9#O&ZA>cC}BaCs!)}hmuZ#rq`hAVYwo9xhCD}A9M19Gq*byfFd5J@A`HAGrYv)o%E z`R~1UK@0hc+ld$$Bn&ojAE#*qw zZ`@glAE&3`+O#BBl*0*z2nrI-|Onrq%Yl)@&S(pE=Vi@ZiBBK@%}YhE2$LS+naRr-WKv@0B$TgXSo>Tj8xZCTr~GBG8q;AX)ZMD z6^b}u=^j)Z1ImKk$B({4(U!1`8{)ccMJM|4QhTuC`2 z?84!t-j>o^vql(W1mt0WK7{n9#}v+=X(2@MWpL|*x7)wvTUOUsb4d(xO43ISyo+jH z=W4^w@0W2Lb>MT8R3}+(Vl8q-%(6+ z5S~@Gn&Zo9Hil)0NtR>Ic|N_fO-{>W9$upb-PB+z`E1t*Xe*p4@1Jj_U%I(pD=LMA zP&W2L3C=kD{d-n!pDN|<#kp&vH_j!Oa0ik&IUMt!UNcfGbG6Gg(nkrF(bfbKDfu}h za7Y>S>(h#fIWuc0ErL0s#0r*@2bU}61BKc~diCv2j@1Gi|mRCu;8C z6Wczu8p(9=D|rf&n4?QORe(mpNE=4pIU}z^PD$rAq>#*!2^26Y=WN6lj7U3m`tH&0%^~m~Opj3d0+90F#WKgN*Z2d1BOucx1Z=iIxdfTOPSQ4AgHt zh?c9kn`v3uNd&BWc-!sC=xG*R?Ks+&jQf14q>RZNY#Shz=OA?=uH?$3q+2U6nmMAF z+q=kow1kX>=v3#i83)@wv`&yuE8M^m0J03nEbAnM^eg}XfJi6UW0Ow%JZ9DP2D+3@ zCgc`UzzTqWk9S^AAbxb%hsc1af3wP|Glf-S9x~fo2a-GT39fn9l4e)jipCis4DBR_ z38YkeeZgT?AI87}Ndq8b`_$wseQpFsC5z0O7!@*-Mv5{Vwm|2w2Rw7sRE$`puv?Z` zXLIwqmCFIaI5^KW8d$0%C2i7ZfF5EN#!e3`0S7#0x1(Q}?4$33TB}--A)a1|B#_Eu zkc=Gs-H*7f8&a~Q(8#K;u`iNjPg$6Iz;!*v#K?1h291w(Pms0AhF~4Do~0G&P*@ z&o$4NBNf}310F#>oj#_ddx)+gc~~+rL)Ig?PpLkf5AteAua-#Vn$qSu;k5GB;eh~& z2qdTkWR9SpUi}Sc88*&$%9(L(yvU_ntA!RmZ~;`JvoOm>c4yRbM^D592>VT|Tt*9R zXjdjol|}4v&je?u>q#BWnT9j=Y{?{J$=ts(l5%sLpTm#oO83_ZG^?`_HY1t|GF6lg z2<_jkS(Kf+l!JMjL~7ncNHV-+G4vjtYi{1z86B;sSGBe$cbGQG?ZL>w>A^VsstwB` zku9&48yNQ(*K0C?+l+oSL~WAR<|yL~$vXK0buA=nJr7QL{{Z^v9A{;@epW=BFdL&) zY=D_U?b!4=1b;rXyKYlv#PYn{GscaQagYh;jt@iqYP@FUp;S7x^n&r!t(?J3Af|JH z{o$UydFxUMWSaa(9m+f~b#(5>sLlb%BN+7tvy@wr(5ln1de9}QllM;1%`0s46?BI*w0YW9{oo38oQo>?ANMB(A%bIL|S52d)RG#acHdV@46& zLX)tK8R2g&n}d~XVB?NK<2=+bTu8CU5K|;d?SfP@9QQr{01B0hT(YVwwWJ^=m@(}N z26)@s9dX#2)OQ~)V@W`F-yDUcnQ+C9dF1CH*PQ zO_AqNnMGJxIbeCtf5ZIqQO5DKzh}6*kfQ>y1_6pEU8*?aIXL$;0j7I~{2vrdI zYD0DEMn6i4rMND3q=_QJzGx~!`F#O6>C_=}Tb>g1)4H=f^Xbf^Ih6*#e&TtMpAL&ug71H^S zEwkIMPn8_bQA|gWLC$ubp!LQom{A;snoG4H5Z3O4YCmACKJt-+yVRdbYnmk4Gi_So zWg=FBPc2vGHu#V!>RG#kz#fM_v?a%pa0b?sCA`IkGs>O-$6obJywat=m$bU@xf_|A z-`D9@ubeX5&kV4`cys1kmkZ_rfuCK<17e~{u_|#^BA54X=RqWlh$C4WVLnSS#~=c5 zJCHc%wGtNc4dtXubWs>0L$ymV>-UHh{{S**EgI?)kRTw|Z8;-PsQt$>VQwA53zwZOqIkl!!fEE=mQI-{q-19q#xcq5in|r6 zylzq`!@O!t(qu?i(01pqKGj|;p#4M1BcKgs0K*v1*VK3RH7&&cOpcBmM4NW2@XEja zYN^dwxKVt?D}|cHw9rXKd!}hi0^DbTkFWHrGRY8-NVbMUB#o9q$vMb4{BikHZep2k ze3>&mL3bm#+Av7l$2~#oR}6ZDaV40xY26seWVZ_oF(z>wpp&=}xE-W%=to0U zE#$zsc7iK_%*?S$ND;%(;Eq8DkPdTCj&z-vI;12I+(f|aVmf3FwJLp@U9TuGn|R1! z7FkQ2kOl_^FmKOP?l@yg_>Gd4(NvkuW6%#Zq*`_XH z@?#(eQTz9JR$igdzc2_V+cca3rt&W6(4l_0ncbrZ?GhWl7btde^#7zB>^t3uVBHNq6%Z-8P#cJ38*QJk@L!FzN2-cBFT zei${hUZyiiGP7x@ur0w~JjizZt~UeE80*F`ap_eBx)Bt{HJaur0?O$a+_96$&tAid zSDrKdrnU9eZ5&N-%KEAzuO-5mgN!3;)h6wJJuHH5Z(ntX62(kjmEb0Z9s$?Jf7bg3PqiAyRoH=4l<9z%aD8q1nI+^0v?=gLU&LW~+ab12?j zWo99xZcjtT52ia0dZyBqX10sWUo3*bm@Y{?^XxwkYT0?_iaEiKD9yshATouQC(vgk zamfJVjP>RfEe7luou}N_GQ4QaPfobV$F**ztYYcS43=r)eI1 zFiet#mT97h?UGMINY3Qo5_tJ|&svXnnA4L>7jGSACOP3VLafY;qXB&h=cpupl@bWV zN64uPUPWtU*7mc>1b0#<`-{b9jX-8|mS9LN z(N`ysF~t$aP@CyvK`sjbRD!5+kS&qCht?xS2pW^x%=4`5imxoE-C7DLb9iq@uk^V~RML;lnaZ z2+Z-uRdeop9%|Vp8yA8(^3d7*spf4}9;d&rPg;Tmk&$6pA%!G$Z?wvVmNmyx7X*&@ z9Qst!35B_4iYGGQ!5-nbuc=XhtJ-A1e8+CIDE+ zf3JMhxwDDMMT$2xlE4c|E5_K4c?&2bJxTW?@~bj#c&$((%X4tc9lF4oV)(}csr)J_ zqGh^@Q7D>cBhGftSP`GkIOpq3mfF_ghn$xRLD!SRFnb!e35Fy~7gkYNX6NHAku{-Ev6S2RtO9f=-W;L*o$Vv^;y=gEw0 zDhEz+lkR%;?^0gDr_Fk@t*Dyv(gYC9_GuYV+z`8Zeb7&@9ZqV_*UCwp{{XhxJm=Dx zERL7b7^U*rg8u-iZZ@2T8T25L_||E@=DeyaVT@t8b0W0scOAhuEI?@Fj~zPYSRVZ6 zJ+W1?5g0`zlQ6(MU?BSO)7G5@(_LKMM+{EBMB!XX6DVPf4kv^hdf+>X6K&!t&#sT(7r$+%@lC3Bt+9-Y3G zQ4y7+NG@|8_C|TtmE3(7jN{Py)~(5FXyTL3TZkD~%*0BHsxUA({ZBbQ^#+{oD9n~3 z)5@x-(@VB#B`j2uI+A;wagO+Rk>ekt+17YInZibiR$JccGUjE&oQ z8OojyzfW4RA|y;+-wv^{!DR;x-zT{FdQf9)vVaRCIGQ5TT0+b`r6rC@BRupc13!;i zni=AF*pcTn%Bvh{kVZQSF6<|c-K3u5K69?v;YP?F=BKlc6a=&Z-C-+`z$iS92MoR;#;5uq_QBxRfD z3=T7p2|aWCsyHUKUy}395sjh=T7gYxfCO6;?=Dy&Nd*|oQ4=~0coV>p*`w4qb0oOJ_&PBT?*E&RlRoWxzN)tn-Nsz<*W`qrvVBblWpH9Uq9MIcFx zg-Zz(g;f~qkN*H!sf?DrfEFcJE1T>AFiN~ir`X5Rd212piU0F}b zORHs5BxAbemjE|Hdf=RMLY!JBm64;ByMU_hoJPBI)j+@PB;|LwzG6$AOV{oy+jy$kOLPk1)o_*>|&o)(xTp1C>4mmr>m=Nw~< z^{AFuWww%8gq~5BGLa(%Y;?dl>)#|)FeuAMJ45FrjIq0wUBL5zNx|TD^sMPNCgT^W zVJ=HY6i{XvT0j`>z}k5F=A)7s5pG~?d9pX|kunG$=lRnf+Iw&=-C8&dge<(^x1c>g zDqP7u(3P^KVmOulT%SStR+55})ebX@Zo?aX=$3UPkClR8V2<@Y?ZkWIh}^?(aV7$Z za$0eYRAczN^Vk|hgJm@(2V{k+m(_dGDUE#j?%P+LJylc>Cfd+ z8>x8~pEQt=OB_O7>Ijexv9j=^9S5}{Th9AniN4Tg3-=HLPeH)PKHz%PfI%D+8D2J$ z7)y+0Nm6hIIXNGfU!_p{V#DOa zX4+L@UzcwjkNpetKDBA><&I^vl|hg?`E3=@kxHJ~83PA2(<8zoxEl>{g!jYL{QTx5Tm2Y3ASGp5Iu{`$>NfWzmjUggs^(@|ppaZ52R{L{8_SW%}9I{5r zuLZj?+75nVeo%S99A_U>R~c!mDiO3xHrCe{63&miA~Pd2lH+RqPeGnAeZ6XLu-n2e ze8|xz0Zfu@!xaOje=0o3l^SjF2^!&cq?X5Xs`LRy06D?u)7G1HH1fD~GRm{Ut+kK| zF`v^XvHrEvlmz*Ru1T8(#Ae#w*;!-S7t155EPZ&u?0&T?+f4~VWr9d%w?8-~f|Kjt zBADhsv&NoGQkD(B&Cc8oKpcvaa{~mP93sB&G7?DId-dn@r|zU{6(Ts=FCapE$7rG( zWWWqq3<7b1&tJxyJl8Ws&hZlwRY=5c6;=A=gZG98IPZ@_DfWdZl77elF49)A0V~@kus}*SO30QEik&YOEdQ(ND_ir>Xz|$gvZ&)WQ9!4;FuQ(a^ z$9k0wtYGEJXj!$Rh+5g@`52+Sj2&|y99rn`(ToXkt>>g z3o_j#t>rQXmT;-F1o>^AgE;Tri%})JOC<3D91*a=1gjI@>OU%mD5ZJXn6<=`mT0HA z1zCN__4fL6#aemAlO)+|jLzGw(ZaJYIppvTc&x7CRh(9&zIsn?WQr6o5C%qQ#^}`G zZYQW2Abm)vrg?G}A?Cfd-J1wzU`9FUIrKl)qPS>gxe`esNM(<6Igka~4^OWLtwf~i( z8?HZffg0ohewivVd!Kr}J+-dXx%2l&C;G|KBO;UN1_|Kxz^VdER=X`UB1=_Kvmw6s zP;tQ+G)75Fxmb0nTgeEK2RpLk?=Q=Maxgj$d(`tpEvHHL`LQ?SmG|vVcaljh!$M+( zcV^+(2+Ew0pmhWuPJKl*kS(y%7KhBhZG&-a9DaVZPNIJ4>e5J_IjrK0H1Nz}lN`hY zGLm`Vk@{7;iT16(*A0Op_D4d`Sj$FM;RT+taqN~Rh2TsU8dO~JDLlIZ!P2nTR7wc z(;fMy$7>u&W?2bXh*@pq4AZsd9Jvok&36T<0k#%uXl0w_ znWI+0+Dv#P;Qs&%XB>cd%}j~pteay=Q5fVZ{HimI`+HTTngoomkUaZ#8$-q!S-HkW zIr-PxBQ` zox-idMdo>j_py$Ay#3Kr#UnDTGM_E}&fa4_cNOFed-|G;+&qy+@4x~s^M0P;z~ zf^a@!KgBiAE?gO1p*leFtumj3r%n&x&` zZ>CvnRT)`h9HS56!v@AdJq|||`U~Pnme;~VPu8^A^y|Gx5^Z?!%&Z2|2e`*RnEZSL z$G;BrzX|wm4MxuWZf^WR3oJHB4(Q|qAx|9SXQ!d`uNtLiIP%E-o{ChdXqVu4?vXV5 zh3&o8zo=hFpxSMCl1V|f1LoiY2?P_L_!oSd?)*2Ycvcx+OSi`58A!s_Q zv+e;&1YmauK9z%G;#jnu5(`Om18aP@Zj+mpNv+!4fv_ZOq^l|2l1a}P0~tJin*t@q zuP$Vk-ryFucuC8<9#@hu!>2rZ*OiL9UhSCaIZCI!rH^URZZzBdO8Me=MVzxUERJ@_ zWCQ`g&u;nbJ!{|m9j3{v>My9q=?iJlkF&^%0otdW{{X##{{ZW+oBTDSX-R2utX<3z z5I2?faIyfyu^Govj3561U(uRJlcIP%wL48--L8D)WYZ;)+Unvr9T0^J!6cH$pgy>- zpQ%c$@1gXVTAa}3jK2fYyg96Erteqr3QHng!)q)yj|tk|TI4t_kOp&&z5f78&|OQ! zqfa)=3u;z6z07QrT44E;F9k?A`ImMN*NzCTGs7dqZ{dsOypra|-&nVfN7E&j7?867 z$7wihWCA$>kF9k&w}dMAW8yxakM+A;CJqR`7VlbTd+~>zp zrAnr*Co!sPt!t@IYjUizMW-}!nFwhkMt#kK*(2r{z{gB<&2(NEyVAT%dt+&+U!+#Q zB2967bVP8&yOLPsDvXo(`%kwp&8#R;8o^hCqtg`B}N#4|CTf zS3BWP7~g%Lbe4}C5}7~KCj}eKPrR$yl;jiXfnS^Fl;KWpGGBRLRfMq4RN8F)Dc1BK z4R}`T!)6QDlSGWLy19m7ED}fvZeJu7+DF|u!Ok&)J$K?&=Ybo-_EPv}{>d-Z+BLNP z(T+&OG7R}^8)dP_Bom*PJvsc;(tKAArWWRT8q#HeMp&K;FgZ|1Bz^(@(ZeGnx=dt@BKB`MyS3{3a z)2{EH2E8i5WR?88c*w{-3D`0Sz&vyquSl2v5CRlYUX1ySMGR!;c}hQV_jiD1_=l%i+Uc4Wzb>Pt>Si^U zPQ2Cvu#Jx@faK(kfc5pqPkoC_xbXbeI$e*8Bh^NuG);AFX?E=rNaH0j-Ist$NGfC!Wp#ChW$0zl!yd_FhaZXE~GJR9G{5hRGJSo-Y{oVfn!mj>j>UOz#PaQDCN3_^t!lH_ZuB>M9X8MHM_*gIRR%IWLF0nVUC1$uhEYeSa{FHTJMIgA4nGK;mMjtTWzy$^AM|f znZPP>&}4g8%pVrK7TTwce4P;**DlHVveIq6a(jn4TvAQH`tWBF8nXpZLHW<~}v&Oz!3ta~Gi z%ZqZSZ!MDK7C)Xb&+@O{pw}` ze&utX{WG7#6+-<9kOD^7PU&}GC|;QQ9=z5a*O;4RR-H=7-z;TuAnn*={{XL5?InH0 z(>)BVa>KB*<%SDIAx6*p!w2%FxRyv+NXZg#N1*6xg^L%r49O%-wL#q9E*KmBUmD7CqdH@q?sSSuaCynKRA7K_JJLFNo8>mUb?-A7KnYFscZk+Lf7 z;A531x&11u$uNz`8|B;bDPI2oO4=?d8$sQUg<}egtg{kwjH4r-r#Ss8wbd8lkc#lC<21SkLlX|?&0W95eqpwkel0KgPUw>}P6zB%i(kRFwagif7a7P&&sqg)9UTyIr(i=NxF+__nK4iN`%eUXRH5DK3y#lT# zG-$mK6}5P+7AISh{{XsHWoWR=o-yC3{{TEw9x)G@cO#O`mWmW?WOLj6eznQTadM2Z zK{Qeaa%2uX#m4TK>_H!;YEP*~kvl^B+2d`3a7NNc85@D>dVhs{^T#(ge%Donc+Y1FHQz_VO2=Hklm>-5Q13(Us~+GCZmzYoy33r1FP9kw1~|T(s(^Hhko~kMxq&`kbokUm0NN2#&g(b>MPOwyPLl~T|C2Js`Ff1Ayo=a zI}^t^^vNEzPgBtv@OCC_*XS! zulZ{m77oHz@?(X+cN+8Z4CLSvN7pr@7m3zcf-#CGk#`l{oxZ=zy?QFWp68nJaZ1vb zr8%LN%KF&52m;$XyFL~*P&Z_;<0Nz)Pi)tJWiYw3wlKLY31)KSk~z=$_OCV8Z=rbN zkz_J?@b70?11lbQ$6hdh15;=kq@QVR&mvn~Lbyj@cBmX}9l06jo_#7MQALXlj)e;C zUq*V|Qd~t4xV5-sP^9_AcFDBy&s=11MPTdtmFzYtkrK|w_n~(YoDSp+_5T1oRf|i5 z_8YXAs9Ts7Rg~^5yd3))=loTB1VT9c$cmWNOl@w%Y=`)Z1A;M*G1%uhuP+gdl1|6F zOBqgja}*=Jd+UJETU|tp0;JC@s>O&OGi7mr$DqL@BPYFeA8n27;I{@8!l4+;%?3x|L?G!t0&N6*D{&}eNjcskhqCWSI9inL%03^>+ zJMr}9xv<#T+V?Q2R&j33+MenQ5Eeq{!a}XKC48@L4hLNI?OT>UA-1%&HlW-*lgPhi zxLH7sF`WF%&V4Ws99NTSFFOcs)#a1tRxCd01E(C1ty67W#`C5mR`S=%W+R3j{{a17 zwd~>XuITgUjj2U@$oAX)Nv4>V^HpPIYk1?3jnWbL1Du|}UfHWQ8pIb1EGB<3N)?P8 zmdGP;2OJP{o_iYc$hGM{SmfLw5)FfJG6^>FNf_XfkUM_0-01gf3JGQrHsu>ok_#yZ zll~s{?cwY5>W&y!I>}=DuIqwvQH-?k6KGhY<;dy@WU(l$yZ$IN|4Mjd}jruxK78|G_i73DiDC07$j#4ySba0;9^ z&Bq<mC-GIrcCV8u^-k%8CRw>0DAtgSu7X&{+nLh~xfLk-_5 zleqNBAYgaxUTYqrq2!$!IHKJnzDX)qo(G`^o_#%Qc{O`!X1A5GCC8LAE1(}Ysi!C> zbJL}XhMJw0tQ1?7jg_3`mP~C`#yLH|{Z-Fg&v9>V^31IiQsutT>-XD$Kse{9{OZk> z^tZli!!pGX+@d(sbFt(&$UO+-81?44O-gN(-P^f%{{V6t-Vh5$${QH;Rv8DLqv=YV zxm}HF-d^>~#{R^!O!sKyh7BI$xP#a6_pGb!RbK2Zub9dr{p-b$qC9|ddJae!HI&N+ z&C`A43xtG#>OYXpXRVX8o1Iow5r^3*#(2v2>Nq*B=)Ddas-?Cr$Eh@HaSRaoq?cDf z#Z`&!efw3*Ta8)cf;*daRv;gjE}(jJCSp*13u!r z8*3?|wS}4)T390uD2$Bc=OdCoTIa0NXAC{Fmhbd25g;8aw|vs5<@SOJBhXh`EWqnljucQ({GKZ*@|1Gz*C6fdxDCjf-~}ta0wuAG6!K= z$*kWb^Fbuqf7zznlp13B%A?XwxyT%jPa~#l2q`9gRu9Bg!N~)V zJDw_8HAoraI|rHee5-BASk8F$9E{heLCK!=DszUVfGPfF ztE3YP2AteT^R$X4f_oM6*By3AxUu7D!2|CfL7m^XK|Rb9vHDM#F$H(1YrE;8#YcWMddhV-@6Mg%G@^SwIn(N`MDaaz7v`lMAxI zKzx-lubO;4tie`wh`jAwH^zcio%Kpk_Qo}Zm(-D)tGm&t-N56Z18lB})h zF~J8slj+48oiR~%(9g6o+qJ|{+)Ax)xujwYdx03jpW;#v>PKplJMSc0n61JPtg^~U zV$Gb6q>h|%jsWAF)mhd%iS~o#qg#xG;B6cLzlVCS{hVZqSoY4dMgcM`hi{d}IL8Mk zuY8Y6=dTASpG}soRmtJ7FP|KDFV8#gjGtWHzDjOLRH=aUvi~!g>ivE@3*QX@e_Lyg}pzJOpSmt63 zY8oh>LJLMg#z$Or;QCUuS1V(08CX^wk~fzK3xH14>D9jCrF3{pc}G! za5?;H<6hoQCn#lWsgZtMoGOmJc**CU^~Cf$)sZ7z#>PuzK2VNw!MBCT9G-n~k@-_s z?DEWHZ{BZ4U~qP?QhMO$wNkdWW`bmyNx1vQ09&_u)3TCVi1*DDFtc1PW3*NY9x?}9 zlZ@jhuO#)MCeXQ}q-RGYkt-Z^PCAi}4_-h0RONWL+m%rpK!@Zx3dHgK zd)2F`T0ttKt;DbvGdcjV#-pb{kj+xZ`kVx2$Ihn!uQVll8&j1xxi#!)ux@t&6@xOq z2Gi}&Bm8L<0k=!(BZ>)R3Is7RAxCZxKZ)nomPm|?Be_>az}TledY{MAsyUFlxs`w* zfSeF|VD$R_b=MigqdGmDCbTX+y}a=l%6UtfH!-;pvqT0?3C7my1~Pp);*s7-rg;>+ z_OY157jL{k&m*rwKMH4%QfJvN@3cg+EO5v`EI7f( ze`88>cSj_ta!Wxaxp?K4RFK&rjfr$@W<2r_ZbotsVri=*GE55$F=Gm{oG2iEHEk{K zArM?<8+qe)c;maa6C;2|0YWfy=y)Qcl2!X$xi$KCwvImOMUinfS~ z+Ca9i0gpWA%`o8jBrfnD5Yf21RksY zKU%XW7W=JK7K%jOCzpZp`!`Wh2@%9hu&Yc491JS39X$u*Qb>-?a2z6rBg^t;5^i67 zbUk?bdeu76LyC%JU$lp~iqmAw85apFw1Gx@6Tm-}HSLqmX1P)ka?$TVagVRQDqE%# z5i%fH(Um|WanH3S$C)+6h^jwy%&bd{Hs1YloO*S@tmW@W<*cK9h)R<)#L*~cg3 z$IN?TSVrr?K!3cfFmvBNlycjl%?K?-SymPZu^ATwB(Y<-_2<~1%A|P$Ebzx}ByTlZ z5lf(h&W1`p#{MlRgO)_kJL z6h)R$(iqu*Ssg$w*v~lc-lJp;RTMdPbBy=TPs*&q;%j;3a;7Acm{a9DfaeTzyX#cS z$kD3|tEep^cfs`k020JvpkxBbtBso{)KXl={$w&l!O?d+1{ve)>rEFn zjzGMY`qJLkEG*h}s?Fy!bXEria83zcFmugEBP!^f=KmBDbegobH25sN2RM$@{q_-M0~= zlx%mw!N=C8lWy6r9TEv`Vm@pF;KA>%k&V4CokV0aT9plYrU{!DdJXWxkk~#VoC3yUm zS*9$+H}08o8*${8CpjI5Odo2ZUv$u?IYebBgE>8qu6XTHqq`CN#g0hGX#Ds~D|6Er z!N@%i6zhd&mobtQpP23elxLp9-mX$s6tzOkK~+{rSQgLkQzSQUemd3J4xSXrZn8Y$ zFs_0^c9Gl;gC?PsBU@%OL2oQ`NS|kxcP)$@X9`ISKKISXL(-b-HH>b2kPPkuW)OE{ z?|k09I3B;7g`|-dmA591nV?W3NTe*y3r8kdPkr8pBd4%E>gf9{@Gi#z%q{Y{Wz3lC zgN~g3b({YHEjAOCq0AjGRIM$$`gHl(C8NH<^+w_QG4Wd2<0LRpv=Q*g9x10(r zWXF)o2H?j&ypPJQR)a((pu-b+Eio%0^FC;~3;`Gi{Q6YMwhMzFm=YPmSp=Z4Q;w$` z@$KzSkL^hE#d9d~)IFf*CCa^8qQO>4??TKm;;c4 zMRBnl{KZdtoder1nz(4QVUo_A-d_Qfnt1mZcGK$5u5&@q}_ z3Qbsz9nwkWHn)CTDyrRcGWl08lN%Krss0o9hC%lA zs*u7Yo^_FA^Pb=c-Y{5g&IvgB_x$LR8GOWuESCu%`padIM$Chf6p%u(1A~g5Z9!_u zJdN=|C9R>8$RF`AFLnfiL!Y=Y^8z!;>A>`=l82dMD1gdGmIwebAbWTJ01Ceemdu^5 zrKL^I$&jIY3=!0HC)V|+QbZ#kyK^i?bzd!!2|Ix3Gsi#Yr8&fV(9D8K zB#qgwC6M`u+4kUu>T}LO^)-C13v%TiQJz>6Dms=D0^qJP7rF0>%e=Nk#O%CBGf5nQ zLY=ud?-A>NNsmqD#p?VFBZ~So2GN=fu3oh zEp23XNLG7|!_Jt18GsnveeefQYDlgQ9#+UljA2f2qdxs8R^?pAk&?M2%jd#@ouGD* zGx<0<$8JIDII6JE1QL!VX(XAIyv8OlqoxN>e2%#um1M3XS7Kw>H$-I0h9BqFoi(%@ zo9$7Cm4dNH04~#mlblq~mHLFFg^l6@L}?Nmc=IFAAputz^*HVPs`N4W$#>)|vJ`bT z>w%K~r;nIpI3E81T+}fIC1JCQ%G=J|64ET>_0C&41ab8I>6W4MCR#x2A@bHY$II*M z#bBi-&N9^Gm=NsBB?$f!PYi@2~okMgZHm6lJm`70z* z4XR3ES3S7*s>>`B+{YYqBq5h{k0Co(*Ekvc0H-Aq+ipZYLT-g%1rd0H!6OQcy|6mu z4gefroYF47ptRL3DC9Os{ILH#Q4oNoNcqPKVZ zI1MYI4f6Eu@88^3Ln9)aSO=3An16K!2n2sl+*6f^NJD&G`;dwQu=8Mq96whSo(F%T4#(nECgkjh>Tzc<2#8b zIs3Q+s6R@g_TkxFCzxZ8=L3vqzhlO0ImSkdTN)QI%Ck6F9yc3sxELUG8*%xXKw#T# z_LLDZxLxz^W>sU{fC(UdDX9vqQA2KLoBUbqJY_UdZvj?UA?bgnm5p%}zqEmLBBCA7PIjK7sH?EsFt?5-iM9-^dlvy0udf`Q-n2nzf<2<>d5bC7(+#9Y>T&FPfAy=P z3C1FDZI%3|o+%_nXpEs)mK$6Hj-cR!+n#B$*}yh8opNRak@j#D4Cfn(B#dK_I^p=5H|(>X8;vr+i*N|e&8((eDm&X%Y|KM=T1*XwDGyCYY~1 zv@*WmEgy32Dj9-~atAoiw?Cag1h(-Lu@Yqmacu1;IN<#`=A)Ec{i)fqATdYf2_FEy zIr{hG{{YumHt*(g^S*B~Z#kVr+!mHKW|PV>hF(bdN#U{A)}GI4aU@w?pg_BZK4G5z z*)Z*FE_^ zm1NwPLkV)qUS*j4#hON!bbHYGB1>gsx2lp47(5(~aC245$8KYbYdo%`z{qf@-lTUO zvFb;mp+(r3#}tvVL}gW)P^w3AN$5v79r}7y5z5|lhDlKQE3~je6l0!q!TO46kfC{4 zu#={I$BlFU052?rhLN&LzDj zGAItrfXHx9pvUJ~vPp(P9Bv7A`AcpGAC3lTU0C1QrO>r>Rx8;pq~4O1jfThx1y532 zpzVNaSZ&rxJiB?7e|M3*0vo8u{{UL6Ttv>GmUSvl3~E@9z;zzfu-jZt&i0~2K*~c& z8Ab|yLF9AmN=`_^QgNFl7V@Bl?j1Htj2Fs~5Urm^_wgDI8Y}Hnf6i2%17h*2e&m(_C1iZ?9lu&iad!!iE=XFPV~*0M;+xkZZ|#K`{uYLend zc6k=#%|W=gIp@AdKb=h~kZ(R`ifJtW0ODReu+hf(KQr%U0+$C%( zuU<3%0M|9Tj9~XWT+)dW50IBZwWV~}N!#cT)OGsQ;7hmn<`#}b+OnjoWDGbYsO5cm z`qT~Pqiqt!A&JN`CPJ{}gU>m}2jNtnAorlb46(w>vRz(8Lo|{B{9Qg)KQFK&(>1l@ zW0#v!(?GLDwE1j&)n*}b3obU2Jw^pfKkro|M)I)bw;Y@n>Q8)RbQD_3q)c8Algyti zXvBqY$C3f!s`2(03>@*>-vi#Vs?xEPlWSt#xoH+M$IL!aWmfrF*c@Zn z^*rOHT8cPPl_64mfZkGV+M!299lP|ZcBbH7$mC5VvIz)thRb@M{GRm{&zoxuLEY9_ zBwgP(%5r@LWTZ~UjH^7dEXFezn8(U!quQ*%41ta_$j{f_vXW(rL|*w0MVts_YzeWlIwD#&f6ye!37^yon#bqaX)su52#lijLIZ5Nz3 zTN^3bMFaShXPje<9&z5JoNQ2IaAq?d!z687e_oYwjmdP0$ zTZ%h}StOZ)s*jU#&(@*YO2vCCjh~yc;%JPGwjco*05_*O9QqMTVTNoGCg|19_Kfn)(DwBh{3_||Aat5ze7TkU z&nXg7xFC*kAS!c`anR?n_No?>!92wd*-RU}!MiQLKi92V5;d!NaWa!LC}dND6r5-E z#aLEfE#Pk^Ag)p%$fbmyq>e~9$RFcd6r$x~8NxsA_7sW1`^20P?}3b;=S>@SK&iAy zeo{k{6myV0v-;2+E4*_VA948!fU^Dv80-FcqhOq($uJTtk1suA9o0{vIX_ZqN|Jk# zJ6NkdkD6GBCv+n+%^BhqJY@0+2d5p#sUq^Hv9NRjTxDE*ppr*!-{DbR8<@P=6J&*f^8qBN1Jb3Wk#p5C5@bnc zR+KlE6-;L;Rl4Wg9QLNXi@3$T-Pi{)M9Q)SKAn2=&(^C3ol8_SXO$sBzKeN9|pb*T_mxkSiqn&AQ@v#cxT5>8c5LVqGN z?N_cx?u_jbjzy1>zbh4|gpsa^k#?6=UBHi-f1w7g&jViC`L`1@c@D9$lI2S_?2rO| z;sy>_a56K3Ms!k%-3h~#%#s#)*gTH&O%kjSa3erJ4ClY&P{7_}tZ*PPu{o3gBjX_R z>N;Ysn}G~0t8X0ALZ&kEhQl$)$iW9AucxkRFO)agpjt^vK}ix#}jF$0Vc@OK2_3#z`GzE#};?F}p|E*mfr; zfO}N&Ljc^fvrYDonL}Yl++(*tkG)i6lw}RX(%VK9#}t`hgVU!&*P1r7TqKe}t0lUf z(b~zqLw5++1g=Ii?O0u-ctp6Ce`k}=6SPo1R9f-09F9T8ayoVHbDk+>e>OP{ox*~_ z$C{RlaSJG78!i}ZV89MP+8E-fk2><+31;JQrAM7Vpnv+gsG&>Eh^i1Yn|#Tg2G&#U>IYo<)K@-o**dYf zyIC=qp~A@`{c&SKGq^@N5-tiPI*U6{5F|Zd%?2gsu=IYE@&&$l5t2Kse9l zc&BV7))XvaiXzGT&D*9YxIIDi`ct2TX%abR&jl60IQ)B3C=f{AbWF-kqa;bvpVheaeZs~GMfxY`&zaj`oHrElgg40 zdZHO*dw1L+YbeShM;_Ifo(AAJJ$wCq>RF>2crWE!M-s|+{huGae_jp`Kr%fl++>X$ z0%x6)NXU*yo?WDfLI~7!7#)4dIVBOzEIv_UL!X%w1FK^=$EGV5+M4WVWpZg{m1HvcY6Ghj zgK;1nAM4oD#1`{BKWd4R+3nr4Z#zcn_~UmNDsp)CrACNN6UT9Ddj=K7%q5mKIOKf5 z9uEgU{d!4m+4%lX@i3Kk=($xjIpHAEJ{b7VwGeH zr=j^t;-s{i5VDD$YnxsgDMil4E;E*HF^*3k;Zeh5fo`5maYt>tbXKqk<5fQ>$Q=MD z03I@G);?|9g0Vue?T8Vaa52Ea$3KlZNrJK|+`^1h;5PLpP}nLPoB`@ObNW+ZU$Mrr zF*ppwpd^LQx3+3rF=T^o<1-9M%1Wsp#CRtI+Mg=C_NHV&(>xe93CxB0;2r_bY~r(x zl&(0+{YtJCVq&V1TQE}S00(w@`g2nhjgl*XLDFH3oxMGPMR^w|o+AgitmPrRZu`P|jaq@xCa87GwQSyl?T)86#Rsp4B6K#ul11b)1 z22MNvbtdxg&$WbRQM5Y}!A)0|&vuz{Rs194;T zkEf^QQlwH{E0%$xiGYuIOar&D;~a5K*i=lZ8yM~2We#HlYK(K9m?oSg-%~DUab$_s z*>^bH!ya5XQIBs!#xqPdHz?Y@)r;emSi#`8r`Dm<(CCfyB9U$`cAY{`uv^Cn`%=RqpPLwS<^Ty^ zGC1IUO-pa~jjL|(+OoQ{+unJNB*HLoRGi^SI5<3z0qANUK3|mW)THx)@@BTSR);^t z3lo4wM+ft*8)%VWaK36sZ!ve7fF+IqC5XTSJ&*qYUX?rZBIR>9TfM`wOXeg^@~7{1 zNK|w6tG71dc%p?i#G4muGlgJ%FnK>pitcF9?ByWLmdxIK%Whg_k%#~Qppv8vl6qsO zQ%#r6lH^QqBS_1EB!PCQC!qDLmaZB&hkiNn3)|(`I!3i_~g^$SggT;RDGeD zer`i!u08TOrn)jLs)X*y+vkjLImXn+dvnex6rU?a2(B!asUGR zvpC(o%*F;wMUhpKNSZ%C5{2A<-M~Guk?reO8dz=TiaVIhs2N&DMgXupmC4Ufae-3D zZ*q`MU&%5_8DE(JWo+jPPfkZsj{S{iTQ1vz(gvSwgL`%8jPQwD%kr?TAsu<=w_{6fX?1?$B#mB0 zW4781v$EviV?Fv0#0}5AM~ZX?%&ky03;caqh)i6o8XS8VQ(avPqwJr83`2%OI(j6Zc8 zQLJFT3peo}%bt|@1RwtM8xoo1}{1aPPNJYucXN~S)k!BIXrBz2E2^l`P$?MOp zKITb~#ALd=nGz;d+X-(hlaL4dIX|gBv|7b1O?eNt0G@h- z-kEUw87CIS1Tr$Q90pU26Y4PO>TyB$Ka`3#bbk9G%A}p%@qd*2yG}=t?m} z7frHw*K)w9c#TlVyRpC>IM08trYcpAWptY1LN>-!Wd|7pI0wIOl{DclW04*-M^HSl z2s^sxA5TiphBlBmR#uiGxCMz)qtoA>zu`lYiZh(G7Si70Mh_{4yt(&cPn&KJ92|p> zdbKQ42^dLnz1^BbUn~_k&GRleqg*fa!zQ3J12^nK(W=Ke8Q*_};DhTMmQ-hKz zvDnNbmRXt`hY@8Vc}l61KD6K5+6%CYY#how`*;aeT!Gx@Ja@_IT0zg7QYtvxa$88F zji1ima2aEGk(qqXdW?=cQkfc8XM`Cgp@z;w6-%GDgb#q6|Ph zsppZCjzRVM5tQT3ksOiznmBeyJg+>M-J{yaJvVjq2L~Wz`kJqBq5RVgvk5%t_eT~< zU{4@txB2Z_Q8Y5<-Z-U&ZIxI^)9zUq^$UTKj=c6h)Z*gGWp#NG?hetG%I!JN=UFNKZErkf^FkHWaQ`emnkkQD4j0rZQwgSzbf|RAW8y`Fqv7n96yDA(g?~Aa%(e z{{Wq4$*3jG$pcQghBa|7o96{d0R(N^o!MM}7aWe@)0Apdj>i7NU4%uAuH!1C@BaW; zT0^!r$0q~pQQk&XV*<@K%_@YMQLAl#`yl z{f8LEM;uJH*Af*NEw~cFxzD#lLdNRyrQDD9iHv8;ia*`$>`%BD$F52G^{7To7_{%W zv!rr~5$+MhGXCN<2X^lHJs5fqZ+fXDX6hpF#H-{V^qKasX(Y~fHsi^`1CBTy`K$56 z9D->KrK5sH*aB^4J@R{J)1LJEbhPsBppkD@?A$DHzuSzFjPgKCaxzatT?#27sYw*< z0?hNMj66roSMy0$Q;cv|pL%Ro__;|VhUwlmTwBG4W|KSs4+kUp)a(|2wqW_-D+_3C z3dbP}^5cvE#E$2$Q%N+TZ5;V(tg6bp0o@}gCnqPbL4oP(n!))Bbr_2x+RZ4EL2#r< z-f)b@(Z){!y7U|#ah{!Nx01YXZ5^5H5=BFFFNvlQT36xtjo} zJ+bRji&^1lWoF&68A%+LBx4+XYE{fRoyG}nt`%NIScI-)Nv+{45Mk5|4x@0$AIQ^0 z7YJHaCUv%qjxaYjr#P#hW&0}_t;BD0A~%w=ZZU}nI5-4!J+d=Sm@Sl#9H{e4APkFa z%e7l0uTVkfrCV>g(Mqc;TdLbe9j)Chq>#q@V$6H9$Qbm<&#|i$7n(wVojIWRYL@XtBu7tlWm}ik@g^ zF4M%a2y(tt9Jc8O3v>961ryvn@j)wyUR725TPba;A>^pY1mn5mk;hurI|Vw9Eox6~ zZt_Ob!EY;ujauo`C1YIm2)vI_Gr0U}-ZP$f_1Um4U}%IR}oTpU$k?+ea)0JOH7XrynyP)|?mY_}`Hnxye~c zjb9nZJ#nAbx)iRA-H|1&$%_GCvz|#~#P)ZEnVCT6%XPs79&_9b9<>~hL=lR4QO2=_ zmN6hwxy}NN+!^>{b%#9lEU`HDd1y~#%!`yeO#?9_ySmeZ#OK<*> zkU8z`R7$Gi%P(%9Xo}L_BuUoXuK1s7`Cw<)9FI=EhZ1RhovGZ-pNWB9Om9C5`H-1+geIhZsqe20nlt0@@yfc7L~-mrQzUu`K^ zsr$QzND@CQAKY@h=K~!6KZRZqU0TC)Z1Bh%~~xrx&!5zZ07*tKpnrFv<)S>T*wAFJ^F)=-Fws% zS_$WnvlV-Im(6ws6`O8PpeLWsvzCX$odA#^HbC%tow|GUg_euQ}?;oO*M{ zdeb73JNGv1@(H81%&cJ`Z{&au?s^V>w6^idZ!N?x~3vO)GZH59IV z<&Iu{%M#`|h+K|%9^>AC19>J5w-fAI4Xr%kh-Ntj+_V&d(Mvc_H zvKZ1#Wtui#y|CCkdYZ3cA-8E&e8*&UX8Tmd)kaTaoDXi4+G(78&c#u2X)oFm1e!_N zw@k#ARP28Y@%YoWL?IhwwMSF?v1ubnWN+_Do&)~?4i}6l@0zi@ZS?X+o7gg{AdHnH z{=6Ua#cGx&=62O1wY0dlSp2jQlCsDMz)S+99PY`$A$sKC%aTmdY-QfYw=l;u86znm z50n5X?SbE?T5YwA)4k*>CTOP$&3IRpQOzdU<>6-H^ajB98X-e;6aBceRGMMB$H9ysnnt#`F+sbiK` z^C6WLr;cPIMw6afw>)u|*ez~f5Nh(TSHS=9zWkp2G zH+&Dqtt5hEx|-9?Cu#EF3&mH;T2}~CAsZ=H0wMB+;~ah;=dD{?)7vBZ zRlA3^l2^>KN#r9t$K`F0X+1Y|&$0EUwZg#+v52I(SfeQ$Z3^rULU|Z&_|7V`#>I?9 zjA+s$GNb&ggMiFEMo9kv^_t3USe;ufqph>~cGI_&BP$nmz+C-%cB=w7FP+R=CRU7X zP0f{Ze~Z2kAP&_-Qnrpriy+LF=)O{y0I<(L=lm+aBDRc%eg_T1 zHU=;W<2-fAH;h$;yoKU>XN1{E6XkCxvc{M^Dyi$Yq0e#Nsd);PmlDJTmrpW; z4so_Jz`5PY&N>gnBD5s6wS*OBxV?o7d2ARfD`$ekocG{&??{rjmKH65$Pd~CfCdZD z1?i4^nsoV8w<;|rMJR?z-WXD8BgXyv7%Ml|rhTdwoC$t)Y4%1;XryjpI}SkPNs@+8jSPH@8nat|Z6 zK+Rc5rf-_eG&b>|5+jmE;pvQhY5=13;#ek%SKi)gC?(qjL5wVoglPno+ z*(7M7y0?-NJd~U%5-JW(dUK8!lh3bO_qUffWX%nnGTF&(8H#Pq42XE-rqD7y4mqc? zLR#iTOi0rFk!`?UbIyG_WBe-Vwvu(HfUSS`f6$a5Pi zNq{2r8?tl6*b`vgKU67Ph@JjE>6 z3dq5|Hk@#Map}z@f*b3EjKSst*cRnjsXpi5rYgP7<^07-T#=P>`xHv;W3k#9SPqgkMlHrzdpZ}R9l&C#O6@D7@wS>+!s80;Ez#Prgt&N z2)0IH67G@C821g+)0%dZW2a5VKyK~UZy~3JeAo`?%!Rzx8OO>q^9<*n->yBx4AO>< zV#X;Hqd6gPI%IU_tVt?b$s74HkF+$K+3>_RFiAdy^c}PHsM%j_zubyRCJS=ymO{O; zkAD7@aDzB+@t(HzV6X@hyHLQS}bA(fbs!0Vr-O=|*4D@hYi51;Cs zg(r{>NX|P_PZU|Vd%}_Jxe^)7!^=>o19AXQ9Z5fzdb4otB)Ema5-8g)-O9t)@&2{0 z$304|vo>iXhs(E-rBY;MjUa%su+9lAKIj}{{{XF8TVr;3*UOFevdFQ>O5+*e_x3ce z0y{_LTS^#6e6>&*yJMd~c|ASH)}p&#viS->a6^Ph?toU1<2d6WHw55z2kS`5&gg70 zNpdZ&QsUVyU@|ecc#BNZ4l|r%Z?X6FsbPOE;l%Iet10r8z#V)05mn-l2-ZntTUK;t zSlQH-^C)#gjxLH+g zVx9z8))AhB9QEfM^*oN0#=2;Pj_2o&6=pzA;tzksQ+XRa=+ak?J-dM{6?6Q%&;f!5 zXk#*}va5-tEX?GS&wuda+M0#>0(`{DHK28s=231Ow93vS8+(9p!Q(vl`qNTNSt5$+ z3D)E>kwlOvRRMU$M^ZWy>zb=@E(9{ETX<)E#77K;l}EAaaZuSobv3-J=cz=Dx0py9 zi0TG-%{H1eN%bsS3CwSGfgpx<+^dp62Lq0n%{(;CBfM~p*=0tPD}YBhs?yy}b@pZZ zIb@PF`#kCbD2xx{UI;$Cb>#ImY?)(i`N9vCOAIS9rj^P}trfIUJH-@NZFLw91h*zd zDnTazfwX5h9Dz=jW|57&cL1@t`1LHmeL5PG&vSin4E=z03p&{RsP_GX@7!^&97?ofJx zk~t)F?@3BGHI*kAj0+O(m?g9jLV`4oIX2)Pz!RJg%A+>vg8u*^4IomO8Rw6#DqHEa z`C3buC329YpJ|k$g;EdAxP!(IT+{6!Nw>IGj%9_uNlM6l@J2W%1W@FWgq_(lBO<(I zL}?z(t0+*djH$;RM|y#!MV8_2W`U%+0ajT7UD6&;IVFw-A%Ym~uHm+xNbckV%UPME zSmx`Kk_#x$3JAwc(`7DVcb0f3Xu`Jij4W*H{?0fc`uqCUYF_b_p(m*ZEg?3^HOZ3V z`a+2Vugs?z81)Aox$9c6mq78XQNk$eUOA@R9fy8L9OnQY{MGAms3waseX(9PDGc+wk1(udKta&s zBm#5SzA9}*Ug`Em7T-^XYEj}vJJBwkX#=yCo%03ep*oQ~A{>uvFw zB9%-a4V|$d#(Vb7QdVZ%{Hd0V=QR?9^QJbj2?UWScMNu-j!EaC z2aY*B4C1t8l$(jx4UDTGV3WdQ3|s^EhzA(QBaXPL7YgKv{{YdTb0IP%o3w~Q?5uEj zJe$o_*JoF z=^U#Aw43IRNmdz2R%AIGecbgK_v=<|BJ;OAa7%0_m4u#X8-P4>w4T({vn!pMvnA9K zNT|1ZME5xJ(iwz>qi?*cAsnNwMnD->?M{x`;g;cE*5U|Z5$=*m3WQeZaCyfg2i#KI zl?`7U3StzBCicSSMYA2iI;W#ndKA>`zomL7wk#~lS~oQh4h zWnU~%M(-3%8WO=SL_|K(+Zpf1N79`X&+<8DEXuMWk~Jh}w@i`7aD8gbvKc064CSSA z-e_Pd$i`HX zdUXD80VTP&ipImqLRbwl)P;>#Acc&vCx9?Ad-tUsE_121Q^>OGadU4H;UfDr#_Zr0 zVn_sfk?eX?Cz?x1ouQTE3lxFo4#2XuK^=M=k&c+-rxh*Ck}U0Rf>@d{@-)A7a&iY= zao6#ryD-d!V`mdC&_m(35OR4u0CWEU*W)!;xvw-6+`lK2IJMhqva3g#l@#p<9AKW9 z>N8b*=^YKUHszs{DAP1ygD^ca&m;QLX3|=1Y3`zuNM&!eL1TI5EJXnsCmTrW0Uq@y z%M(K^Xl6+^w*;_UpK9lOnfpYU3{fmHd3M&3!wR%)meI$yFahCIbHM4%T1As|ldPf` zvaBuR4Vh%_qp=_!{{Ysm+&nB}Nu)8esc6hNBo3V8r%wL>TFq~>%R5^InnN*I=g@=L)IlM(mL(IawhAUNBUtcy(%4E3w-*5&4qJkved z8&%LM!u`PH?ou#)a!+AY9wL&9*P3)_ap!|6!jjlix365~zrwOtxzy(<#M4KPd#I$i zi)=8+tt7r#4I+_%Sa#{`OKIMixB`BvECFCb?#sC8y$>S7WMt;#Ur1QsZAazeRdu)}C z-3k(??vA))x4(0q;-ZvIGhD1FS)*Yi$LF+aR|f>+_=1+lu6@lctn)HSD#;8+J{STZ{qMBL^qkR$^O7ju+(@1QR>7fGYqxb-*=!Z6aG( zRQZ8!F4QDZ!c1!2#{B1ujy?L;jo5L5CsvxpjEe}mDp6u@Ajo4pgOSK9$j(O?>x#IW z3fxLn9wmv5z$gyZ=t=!Q$*Q+g7QI*@L$Wzn%Gyo~dLH~%cICLZmPS%#i5+8&`l-)B z_3QaoQnaL0smYsAi%1}Y$ypRKhL_BbYaec$8fCoRV?}P(_NXl^@+4FqVadxIofhC^#}Urh_OmcJB$3qg;MA9bIT}T^lI3q~WLv9=EOEJx;!6R5K7-z~oRmm& zw3dY7VzOy2P|opBbGku1ts#i?-Rz|F1ExpgEVD%zbXa4DJB)ECJ6r?T(>N!Js4Y>Q zg3B3YoW~X2)w^WDk;c`|(ntjL=sh!6&!vKy*IqgbPi%70rb|#6w)g1CQ$hCVrb-+tO zFm_&mp&%Uh&+2N`mz6Kf==+x>+Z-uz>N<{xy;qG`MC{Xt!j^Ss0JcxyO+yXU#1o@H z>m01Ct1!Z_Tw#=Z5!6;(yy#91mToR?of|fmo>bEn^CX$pNXnCpDEUY|$@CR8>l_fH z+uTJn&ZEzY6(N(oaEzzNcXL2)0Aa%SVg9d0VEp_l!y>Uzqq)N?q=XfR|Bqcz#pL}zI@P2 zc8e-YG*Cq4ZKhyA0B7anj;u~SO;rjlmH{;K${D1QZdx!_HscG9GN-;xSo>A0B$Gvd z4EAyl>!D-!5_x7wlr&qSm4u~LhH!d!@9)J;n_~}> zk}AP(Df1$U01`Gkk~t%%9CfJL7@aN6wDE08M)>AaxQzA22psyJ#-zKpyKA;))9+DZ zjhhbu3ecaqF~K+ul_2^WrnNCn7cJYE*(D1dkXWB{O&n_*F~?S8%P>#?9@rguWRO9z z{JXC(F+XRH;x-aCc`cKXf;s`y2eGQk>#{U*k?ckDAt19z*dq#Y->y%gruo5;NaZ6% z+zYW7U;ekfCp#F<7c9i{q{I!YZWWcJB<}M&05QlUoSgCa)s%zEYuKA;hX;1$3_mV#^IhRsa(c1?IuU$mO%$8S_b@BZ8r$vLj)4CFv^dE;lb?E}_B(|^5fY+3 zvviTN*~tX%JZCr<#{hepp3FOzF)Jm<*@FD%Dlyj|kAJ06qJ^1Z3}SNYGZ(vyg)T~{ z85jeilb@*=>?=OutsK@>03DYcsp~R2XpnRicHcvmKJt5= zvqh-fLkn6(r?BrR<(+BuonV}eHjbAycM+*0LE+72?6 z_9DCTw$E!Nshy&ZIi_hw)mXG0j=LxIes) zV!E&&bP!krz~uL;%-EH(iLu#%fHvTx&>p-V^_-QCifzbMic5ErM+nyz@u+o7NTIXX z_W<{(ZEpO@9_H;`c4b?9VS{|w;1A||8lK^09$fHUKo)lqv>RJ7sOro>!BP(ZbMl<^ z6vUDuC6S@as5^nlQlp{t&0#8Wn>r&aBHi7?TtaQ2w~2=6*=0$Xu~D1?F@Q3AXQfKh z=GkFL(VW7?;+}IDRs${baga#hbtjIbW{eUl?JB!Br_3?91|F4v?C}7}aV6B#7<|N3 zwl1-+y9{kyo~PEO(YD4?T+F8(!vhx4D;HJsglY(lv-*xe{6#nKM|e`}_o3K2b!J+z z9I+$CZmN^qK!xON7FP$Sry!HVVwx;EUvRlT=tte?%a8eE!uLJ@|2DDc*a7pe+ zXW0-bAu;SxbPD0Q81(*iGD{Mq=!q@L!D+TQq8L__rUB{BeS3ARsN|H#YYfjDwDY%` z{z+9TJ9Q%?aL#)Ab6U2SR!YxrZw<^XZc$s#1cq#9DsTY=p4rDt! zs@oM*f}oIl@!uHco|w3hvRkTKwCuB~NV!~o!X_0>OInF^RoagJ_ ztodk{cJ20-h%7NPPaF!xq#X%U@|@rUTgOC2+bI6*OKlq4T}TX!tq+@-4o?^(J$jGB z=~_V=Np05U8VF+CQfRUiNsd9sZh9Q^gVvdIGtVnr$Q6kJK#4?W1AuU#0DZ?N>rp-Z z+fGcdNRc*ovw(MfJLGq)sw3C+5x zA8&|JGvCB2UcAXj3w={@O)>i60c+E2#-1l?qWtsV1iFD z1|4w20Iqr;dUS9+`(%kec_fUqZro#@gVvvMD?u!80Ef(GJWU>Qz46=dHP>+v+sOpb z87>BPr{5f@0P~MSP=W-ks#t~#BFfk*Sn>Tjd(_t-=@Lh7t0Oe>g++lf%+12!FTF$% z+dPRpF76sXI7=1)WH}hm8O{!UYY9oVXDV((NgSgM!UW2*y!0(EROZbaM(KMH5ag0m$Pav=d87s&H(lDA(VN)uxUD;Lv zlpdfF$o_RPq|@BmKJ2bF{Ptpv=0GjsJ08@6%^@6d#~J>;YG@3CNo0}QSrClQz_BcP zjGj+5Vha-`!_3BEDU2*}M}Qa{VZy91_AUU{vq?mD(@nbNvP zD@wq|g?6eEOrBQ9Gr8<9jf)1g}{lSB65xP zZ?lc1SoX)E^!35*iVoTd+^KJGBymQ3uP!zNc{v#M{HkRPZUaM;GOpR@btBAE)aTb8 zoK!6(z?7t|wg~~s|7%3LW-Z6J>M_vu-*(>dy0T!Kk&jhqq9aU|{{Xd;eDi+L~>Ewu?hC@e|&d*{}c zR4}Vg%N!iX&hC{12?RNIZ<)y_`=Xy3Jj(I59C?H0X8?igfsXX;bk22BF2&nPR^$!v zxD24kR1C%dJe-lnKpbT9Dk$w2JD^a~BJyxrK&PAo*989nAytqpHxC$aHpD-AKnmPt zi=STDAJ(*f(56+ANRq{8l!u86FpYa2a(15Flk3{Ea*8%mjfI9{@%d_HKfhcfT>%I@ z@>Gta=I1^6tofmlWP5o+ZnmCImp)`|?id^q++&WE`-viwRgM`hqn16sVUp0spyQ(P zhEljW@000Mh^?bvBHeJXTep)E#uNn^+s1G>;}r_3k%X+)!=p%6L=Dpglw@G9Kd<@k zNpK^NdqVEREPSw~n73ihI-0EnODt_1w-LZn7JbrgJDdBUs3$%7z~ikwGqshK*^V}z z0LC+upKh4$MKrm(krifIxVQ?k#BOAUYwLF35CKF9_*mlW0fPAb#`F9S#FB$FH zv~7;m*xp%NfW)gd=@o`?z&vN)o|OQWRaT9L;-KL-9&z96+NsGio(tY0ggmpGqaM|5 z$`p^34{DuYisIQ&v9_2v0fL+p>VNvxR@&l8A!5b6koZWIN$2qT)|8hvu{?X0S>WCY zNMs7_j-V0<2ZPifdLd?R^hGsSj(Flptt6N;G;qomMrQv2u4E8F=dC~sS{K9+ylZM! zB{={wC!fG{1M$sS6M3bBeYDWD@Oh}WFrXz!X2Qru2;&^7?0Cqlk8f`^)QKQn$lhcLDgwKgk@$>c4z(J} zkr`$PA$4_<2=?w!ee;}-{MDH5a=*NeF(k;X=f(>#VVwJ5{WHaI&9=&?DN5uw64}Or z;K=fai+qkjj~VB<1QGB3F;EnA5-*t%TaB-mLzNimpF@ypD~6RK^GH?%AKixy<~Jvv z+3irQtdULrxsha5jZ)anCgwO$0LjLBo{BP0O4=Nzj%gCgnF}GB7AOI4ElPz0r*BT< z-lm_(kzr+?Ng2YdiX#D4fjtO0Kj+estybkCSetIxTm59gSQ1GfbJINHtXM2AvgJZ0 zq7RoFRf(volZm%992TUaD2hCc9TB%MS3U8^8R&nlQkn=AOxISi-8h5Hiq-yPEI#jC zcluR(m7Xasm7U{Ob!#};O0iz#=hSiszgm?fl33NuvP%e!eo1q;XJ7{yAo6oc7rDz; zE>qBrt!-y$i>ot)UnbeEh_{bv+yGWPat}`Y4@$Y02qG>R#0C(2+e!L=o+_)yxy&~f za89y3axAhr5=Vi+Ksfocl2{YK$5T)idv|nbH#>kAbM35Oyw8jed$-kfa9(};@C=0*z-mLiTBLC?2Q?mw+m ze>G8UqPdzl$jqS+1bP~dXNuS&w*LSuDOk*Q?Is(xLgS3}J%=@NTtb#-<+zcRw@Dh6 zjIkX(c=R+%T)hsrH5iZmz(H!e<(0l+jDQz!IXSbBH)QS#BCc5yMAK04V)gw*S|jXRo*8;ff$s&GiO)0>Nd=eTJS zLSEpm;?3Vark}RrGacubzhnOBGG}vS^&Jo6Q9qXmmFIHZJ zgE8uRk?mHN-Ycl4GfJrO6)4WfV8?&J)1Zw$%RJ1vm1Ob7b)cH<@ZqiNaPFx;>lD=%Cz z&JS#UKU&FvsGUr)nK2o{u_`mr9zF1C{me3za%2y-90iQF_3f2}cK^1j#Qc|jHei@I+y*peGKJg=u5W9y2i=M!WR zw-je@Hw;5<9eM4a=|$DdlS?h&x3@)Pjcz802;0k1h2U^<2QAk;oRdqEO)X5L89zeN znnQ0JLS%(u+lGzymOb(M&{Z7mO@-!RyfX~5WA78#=ZcMFk|=~~5PhmO-WZd#bqAbv z_4cUVDDCbbETziI%_M=r47_8G#1MHurYb5aCv;nfD=o-=(Q9)U%u3NIc@pl5H4h^aNl~6j?SgPWDyWMrvq>B6 zk9b|KpLBuGBj2S|y`$K!cO98>coO7Ym^p#p%PhH4JLF>ob?QB7mbS9ps@uVA(q1g0 zJ6kJg&zT@@ik-+f9Dnud#k2<685Nmhif~!-Nnmn%egdmKs8-z^lg%@LZQ_jpRZf89 zVCOxKXawXW`dW|P z#PdVU$JF*-^nnr5DMxtz00DL!L$`J8itdYt<6Pk$@ScUj@U-M%yf zX~*#6jzJvzgX>9Y5=sQIto}flw(>(W9_l-cdLLSHahfx8ZEi9vSZ)$eE<3xXR5D2L zpu{6~IXwKQAZLzG=GKaQn}7A;pXFf33P*GNxT#UB?QZ4r=2nqmX4n`EXMngJM|y51 z2{iGsNB}!y$u5X0rqLO40~_WIP;r5K_Je53cSUObPN zrcde3HSR6rjtOlobp|n6Ng0M2qiEVg&TwPhkO2S&95K##!}NI>)J`KYnURN+Bt=_2 zbIANErv27b+T~*|Tnm$p@N&h4RI{*~i)NUEJiz%y}o*gOkQ9mzkK^ShFl_s*%m* zO7q)oissxh?qWA#hfXttjyTVH{A~TUJQ*VRy2^D$TRZjICC<_2WRR*m;{=oLEA}hx z@j(@|6JIr~GS7#$l0X)D0Qqn+lFBz@9f_}ve{6pNTlky8CjQ9H1?Gi(k867ht4OPz z%%HG8D{b0%`e5MI#*8a_vOTUJ%p;a&(5Ykb&%`!&7gwGd({-rrZnTRDqgWQ+SDNBD z&r;+75EkcdPBES{ljh$M{4)oNym4!!Xj-f=SW5|p+en$nk~!38Dp&yfvOoat;PGEW zcxKA_9~A00+J&gU(`{Zhxv_>(9J52o!sHOF%0Bi8$pnL5c%Bl`J|Xy@#aTUPTSwpQ`wV7tlattHylVJpM)yqjFqN@TlI5E8Yg5=S^j{Qh(Y!V#jc)GNHMCf#{pRK5C>ZK_ z{{Sa7)A)+_#TUA!nWk!1?{hATXtG@+U^Gk*5ve_oUBnK19<_m>UU;*_o;2RNp=m5! z$#)#`hE!~vNx4Bio8}qs*1Z!*)4XkaCyD%58bs?B_P?7^vNA%X5TGgGV=SjFo=;BI z!l=bme65#_NyU3d27F=hGVfm1*HCG+o6GB$)Zs`p`x}C+Bqsq>k@I!H2dS?h{?)qD z?4y?ENhgg7iZwYKq)-cio(Ti4E9-9>co)TEM!D6d*QOd*h#0Njm|zVEW1KR!Lq{t1 zV1DZ`@6XAauY+$b)+bBGo>E>nh2<@^LHocSK45x|PkQ(+C(0D9E9zrHbQLaDC2u39 z@V}4rJFWKDQ!$u2nRfvis*Vl_Bxk=$^?wiehSuit+R*A3S5Vzv6|zGv(F*gCoM&&| zIQ2f2@b`!`8T=`Gaj3$wt-Z|NXmkwGs9bIY^k1RsIj>6aXNa!W!DVZe6G)6BMd7@+ zIVU`o`ilI~(Nt=v?vI?#a8YZXEc@TX_LJ%c{wr;hMHG9kBVoCM?!ekdDszGf{`3EwQCpzT(~h;`dM351S=tZmol^Z}y0&GK+(G6>vkq6dEWGsxjGp73 zme*3g7c)($rLxHOf=xy^r3|2Cg=Pot^N=(BE7^r8Nqjn=0V)+;X)P>$H>P;&ShSu9 z;+8lkP_1s#;gl~RbUf#+eG}kc6nM7XZZ*#jM{#>|2yeCOGB)8N{{R_d)03V)zJ|Ua zS!9{)tS+q8rW$m6nj%>b&5$vkFfq>^y({alhCdLzS@6@t-XQRE>5w*`;(IvbxV5{} z^ESdmAwtnN|I&kfCB#?u`NC*nU zxhh9)4SrXAANc3uKZS<&<3ZL2oo#yley65LqDbVBaIRM)47k8QrF*x7zi5vX$8oJ{ z2T%^W%Mpk@!t@C}fehc~W_78Cc|!$M7FaSFrpt z@jUnbDDfY}KN09R+HQ@mSjQZ9vjl5p^7j@a=Fb_yIO*$wUw*UvUONFAb!)?#bFzz$ z%KNwXws6lWrGduOmL8p>7%sZW>2+`NJ{$4%mCW8Qy|$j#;q<%7WO?GZeZd&YF3w0+WBz{KRa|VY*{1Tu0Sk}k&({? zbkD7Rb;P_X@YS9sql@PLSA9*vBE^*w~@j5 zhI8AI>-Dd2jjk4NK34#FOR(-G6^2Ow;ClZ6KU(~k@UM!lbZuQ)3x)FS?g!4e7;dD0 z^@VVH+L{pfAxkAlu{vclqi z9VM;$9;rMYas`$s=8VLw>dUx?Jqh;XjP$Nv=0;Z{JA0Rz4t~iPSr%CbC<2^ko;meC zmDfhg9C9O_!bK;jJ5&yz&-1QlQik5?+CMBuwGQC9QPZ#2>0hqJSn&Pl(6y)D+?d&3 zHUSsriSkHn^!CC2wbCWPK+f3>FC|m1>g4RLE>a6ZXVKD zVK`TWg={`SBxHe_(lW6!i@DQFC_vHxfVc)%89Y?WF5;)xoxCv17}vx-p}h)ZS@$XSlQ*1Ga(x#Qmn(*7#xbVkingHpDBn^0PpYL zpsG{3tBYHWi3IW~ed~!1Ha0W$1Nzn3qlB);Jm>B)>z`_`YM*II455KLmA1K7`s85! z2&;|qMiZ9+1?7(Ku6ojvOy`z|4X#=X8+)s;(_6-+e6t0kOgA0^oE)z>8;)=fwRs#&a^rL+&lf&(ryP*PD*5^?W;L1~Q^hwayZI++2B*$7YQjs;A4lUpYdZzcMdO z;PQDrd)0_!wfkg`Dm_<{hUOg+H)tl{eE#pfWmPTi6jBft`>-Xoa zY1#-QiI(nfAbT%N^8(~9gb^;=um&Adzz32oRX3cUyA{cFwc zrk>fRQRcEZXIVyes^=YX*OC5nTzI@%jinZNSgA^+n~sNNc7M|42{)M>u*R{F4$|1k z9XoU+dLG=?HO%R2yKE`)5x<|6i8$@g6;j_>OQyB8UE3|uk{6kO)r@2w_|9{WdUKmu zUP~zDStN!edxZ0YNHd;Krbsx?rE|t`t7miPF%&Az7`m*mmPzM;DTxY+qFv@TC$Z`V zam`heRb%p!E+t5VF82)@ob>0eI`dUE8)*_dg?rn0(jmGbEA28a@Cu9q0me@_=y~J= z=T}obwxK1oQcna@NF=mL9LUlyLJMP$P^Y$iD^)ndrl-x~p@_rE_B|H%%HHRDK?IV3 zjMB(}vhM6X0nfkktoSaXj#Z9G?;Tfe%ZpoPxQS-m01kj~Hw+d$4tr*?ZFP9;;`5sP zkFrcW(>7IdLGRIrJ+d?Ot;ltI86$~p@D^yKXXKN+B>r616>CCM?9XE;gsRj>Qv|lF z4buh3?#R3mMp?6-8{3nNjCA_v8gm?ys-Z-R73N1^Hvm7M^Qj`eHt|T2TP7JY&R^yS z)6)m9;3}RKRb;uCz^tswn|VBO>DSi13V!qv`lerl<)eERX1t2i%AA{}TX=$_Y4^EAl21+tVeQ(b;;B-4v&GF+VA^c-4N@5{?Pf5I_iC!p z+bm&~)OPAVZUzT_YtLf4ySi33{{TBi8*(89nZfyoUf9PyG4-pB;zf;@c3It;FxeYd z9>0ZNx4O0r^MtnZr3G5yV;EJ&JAMS8QCj_ejGwxE24PBtd9G6;9Yo1tnF)ZTrC9F( zvjfjHfpw|cSqSEP+o&!)^=OzVEXYsH7@mNRF^>JQQ23$?sNz_xZ2s9BOw7{S0?i&d z4bN=)Wc2s0Hr&hN84_!eb#r*ETH{id^m%Lv&fhJ8ZQ$nYr_WOoA? zAm=CEwVoC}2x&l+!vZ7r{2 za$|5lS;z&1u1P!FIp{dRz`*C$uitpC*G;&Z02UUtg$#D;zcVXfuF;Q|gPioo*1fDQ zF-F>-A3Rj4(sH@<3;2NvK4%h4M3)lhEXSuOziw*nkBH-%E327i04_GiwC>yq=RcS0 zUo~l-Cz|(BwTfk#jIrl%a1|7SdC3QlVf|~lx1Ijh&F8}ktXX+wQe#!m-e9>qM|^)e z`fL?NR@OXvnUC)`J;ZpT7YjUT=Sv(htcVUbWZ<8u9Q)$B3$1EGBUok)8zTsO)0ZpX zBe#AzuMn}+6-;Iudw3?ekz7HOE}hu+D_=YhrmuJ28~w4H63kMzGOnl@j%#~lFX zzK#yjM}8ACQulAGIt#BdRKb5PIdVu+cPTx80%#3(k!*%}mLgT z6OyaX1M~j?Ij+M^hTh&)^JN7jgDuYHXQA1&&tnefI9f(-pW&D!jK<21BSZVvZxB-R%wvOBOfLHW@GLN zIme|&npCRu#?kDAsa?_`%KrdSk8gU9Wfpf~sY=?TY7Y@u8K92Fc8%0-lGa;tj1Ess z^%(EN2THEb6N28LAMX$6 zU3BTDcHwbtw_#zowzd~Bi&)Uy#1y3HHz?zgz##G4*B#AfPpBJaN#z#*0JtEug4`@@ zsyRm*!IDKFf}yEr`bC)S|0bTG>pj%>TAk;9S3I&B~xxycm^O350m zm@-HLs~q7*bI|7<{{TAFwFW4HpDz~#n_&?Jm<;DWhpz{=D>mYh%Q{m=EK4dZmhroY z6A2}mVg!tHwXy2H+Ue@c#K(A4J=&AI;oN4QKy^C(%Eu3H%$Gtl(pcF6BV(nAx7 zeC?lQK+9q5I$?>nmm+z@@sKcNP@;%eV#;z3ROAIf5Wfm zPLj$5byh~6NG)4pg27dpPBH-*+mLX0$fm*M+(jTsBX22oykvsFj=w{n#;cb@PiyT7 z#-!xn6Y`9c(08iI0(r^0;bbth#x_F99x!o`df;*Hc>|>v5Qt-j zGdsS|on?uN70COff(h%49yqBX5;-19BAgE}$}$;wJY?V;;OFqC1ukGqnGP#&JYgo5 zSlV}Gkp@(%k3u=Y9mhYFIU|uCV5efi3l)vCxW@brPbVOZWcR4q%rkk$UBYE5Q_Bnk z5)T;}2acfkKD8`R%FT2UQWY({7i04txEUw6YTcq-Slej|MAJD~`b<6<2Ib6wG3I%E}mp z^CKNjMs}Z1t!Sxu;<|y)nKVeHmNpC*oM(*Wb?H@_VYG;$f3yZ)-Id%4#(4G5`RP?o z?#5HQk{@!X?CTA(v@5%GesdQ2x^vS$w2JJI+`<)C5td^VD!(>+Uh1?IX_)`ArIpB(a-eva6_UnM8=O32?BfThD zJI-XFpf^&>y%lZB!eel(t=ogfF_3<>dp3RS?BBX?_&~c1<{(%>HHmTo1-ExUOx0AKzRPe7qhx8eM34YL$R)Gew<8>9){CPYLIU}> zjxen>vCPrP!=9%kV5#)!TP0<&%_^2+v{LzgOn27MPa`n2l65T`KO}LGSdLBs>}z3e z7#P}HuRe6#x2T1SD{+QmMli&jV4jCPt1=};La7tvu=6I8Uo!)S7~PVm)Q?+dJ&CMjHcMsw(llcOD~+`8AZS&b`E*R1Ft}8J9$2B#ETh2wH4YyxukBGUZMSDr4 zlHbU>`+10Mb-gAO8Q^(Dbv%v0jPdD4%VMxJsv1UCQ6W-7xa_>(_RU(e>yk8?`$+uY3zI}CC>K(HCwamZ%l z0P+VNhq0(-6G@Gv&L?svbCP!x+@5;Yv5zU2CD8!8m0TU!SlLv9=OIbX2ey4GMKj59 zb#SL-Es&XF8<2DF+Z=jS4vH0(qWRs9SBxBVt6~`;4vzyVjy=Vhd5$*s><=HEXrn8k z{5LEHM@ZIbHl@TEiPU3jE;|1Jp7l!FG!91T9zv%BW>-1nllgJ=^s6ka%@krtWw(k2 z`J+-8x26ajj)e5%zG^o~72Q|KRancTnMh$LVYC7WAd|@*1rko@9a_z?(M-@y2yL<- zn`)>Foac{I$2C+5BY5O%OICPH=V4*f+(ZXh=iq{_+*mU$6=W;o+NpsV(3;)Pb0;chNmix17NsD^pV3#io$ zk$uC{%xvSfdH(yJT#T8aLV$gU)lD;A9c&Qp8HhA&}h6ti-I> zk*F*_i}~}+e?? zuBI~PW%#T^MT=ExqAlj|JRT zre!AK_>O58JurDAuOs-XTyFO{l5R$n_H(_P$B+yKUTF7Zbs#bRS*)4kiKIq@%ZZ)( zM!R<(Q&yxB&ZO>*S|~R8jNF0FGCsYk8+f5m6{QU$M#?wmB<(!$j&qYur1v_x2N+7I zD}6PM(tODF_}mvAGC|<<{ArDIKHo0p?rYf!k0GUE*c^2|2d+O#o@od zGdMuXUKIoaKg5ClMIO^o z1QF2o^v_z2-2q8$f-@=knFi%8o<}`;W1mA&#=+8ShGz<8IA1V^Rp>xD&JVpJ%&Y^9 zDPnxJ+l5ikeSaRcag32Kp<>qM7_u{}?D@8|VU)1x$4aQCHQuhFjOueAJ2G>geX~tT zW4DZ?XeW84Y)Y@00Ubv;TpoS+{MDVvEYPW74k2PVLVB8|Dvbke8WvD5lRcZXa76@* zxe`#&fTXTLT!V$q2=(`@lN@?=!7;||3ac}_0wm6IFg?NV?N*ur7jbF4&9Y-GLBPtBoDRU_wPvGoT5T0xSkLb_4VzDx4szXj^!EHJ z29f04AzUhtl&?Zh<5DDGTHGg?>$}5LhDPU^rwv zj1Eb~Lhm^UL{bR+jODOH5`MYJ$A4b*rbhV|La~AJ?_ygAp1-dGvvrbUT*yHzW>Xw) zyJUo&^QPG_NXG}K^vAt6(rJL(xX7sIF{liodoj*_l_kr-Bn<*Y_%VZcqbwuO%%G9L zCmG{B4r@Lr5hZkq<&W&{%{xZqq=CNZ$FVrixb)|yl;I%enk|Q%Z)vAbIhf#}3ZZ)p zeK@9DsLYHeX=FIw!E=WCdR2#b;f6VpBDnw)DF-Z!J7A5cJ@e>2O-F3gS-gVD-Wk5m z;!EprR%MO2We?B>&JU=^t#rztQq`AYIc#(8z=aBzE=s{{Z#sSgda?ts3q~Cz2`MQr-NbRJa_f zo`m3nd-SZXk&~6!)@zAmC1-^kqO2cijL95+^ft)C(@%a*);LoNfNk;OHCukf)7p)raO`Rt7>+(=Tso=V@)AP ziKd@9g+j4J1du@k@FWg?wMo)g-Q)?jByr~KU%c4$9e5w0^rq?ehFIl*qRVe0kFraE z5;Z*;vB^=;0pIbfK4eK5U$fo7B4t%$BKa+W*8`q9el$)=8@^@KujaIbg^AMM;tkVI z(cs3X7%UDMdBEUjpL&iNMZ{3cJ-n!;*;oPtF&>AJ$idIJ`czBv$kE7TK4at+Qp!}4 zPtBeVZ~({htH`BWWWH2vNjQnaDC^Mo?O4Uhm`d`IBCA8Ub4i~xNb)45m}iso9&?k7 z)KfIGnWBr%^Uc!9ES_22BOXcIN6nt(e>zES?qY?6R*>DcWZ1J78%g7hys;fXJ^r;l zz1_T!3DjIHrX^cwE)k!At;WRBSqIU$gFWF4VX(0XGZ%98ftNiHUm=1FIHWoa(1ZXB^`JF#Qblg~Wnwu*{c z66!~(V61{Gg;@l0N73>@8SAwEzlU16739+Vvt0R~XOncQN8Q=qrqvtw#f-$6G<>q#OFSpcd1}_rZq+rvCB$j z8$zFKXRdqy04mNAXz7e}B8F?Fx0)HROIp0_e|&yLQJ=3t-{0PnCn+9wFA7Sg?B#k> zSr#c+0V61Eh{+p>{#^E{gmAUhtZ+hPgvbQ0T&V!(p8fDU(RMbF-<@S>-MoP6rwqR^ zUbq}_*yqsu(^GRSkVd6c9l_OpZO4vJr%$Iet>#G4Nre(D?T2iY4bz|R4`Wh`r%QXa zh;CjtqD;G_AoNuv9E_e%9Q|t3vlLe;OxsTcl3JMxpD%KmFh);ob^ieM)1E0pEOTsIe=(HJ7wtIH8q`&@{|MM8RYAOcAIhAO(kVh%~(jD=%TNg?x-&UqZ;9lt8m z+9%MjX*&!MG)n9lO0gJR=K`4&5xi-HjvT4MPB#vJT4-5P+)AubOzf>JvKEXte|!%3 z_N#JBWfJXzXr!4J650!eGX^~lGo7ag2d5Q{<8)J!?yCyo6^$GP^9O%Z zz{WuO``4e$X(D!(F#(X7BHNRJ$ieN-Ip?RnP4<_4&v%bCCSD+`sbfYYeg_yxQiEX8|>3MsVc|00~z{O zqBL#3KQVT$OeN6dk9=eURpz=@clj_%jq4Tw2d7#~Nf_IfMo^Vtj@f0nlHFDo4A8{B zV@OBJ06gO(1oqFb6>e02Iwmo*tn9$b`Nn#ap8dZ{&YI2{u5E5+k8Fz?x0^ByqMzXP z0N@j!L0XYGo#m9xvKYVud0hE%#xs-cf^uu5-N`Tq}~G#^k9!xc;?fTSXCz!ws}; z_E4{R8=o>v5_d>5fJZ^J0f0SgmUP@rRHJRlBoQ~0G?K;&?NmnxInQptU(TuC#?Z+l zES#=mh$Mikxa5WGc*)H^BEMuZ`F?KDPwv;HC6gIq0R_W((y+G@+nCs&Ol0x~KQT@o z;}nmLG-Lo>@D1w?qx)#-v8l1_8YT4l9{25X}063!XkB;6x1>5fKwbJ%Cn zrH^Ao|@>?*(5M4wMmf6NvZb4JmC#HGnQ@lmMbz|pwK}s}0MqJ?J za0$n;$0xXR* zW0Rj+a-N1#=4JVsHA&2<6<$4qX)JM!=NxT0;E~#@hhgQ<89=IxvcCPHV?Rvx{{TGG zB{N=;vQOQ_tY&ZGX3tKXgU{tk(uD>^RakB@u~X(%K`BNMJ_RJpt$d$Q7+OW@%|Mxq0tmR=k$wVG=LdM6!km zgRnRlQrRGN03*E>Ci>A0d;jJu;U43s}~@^kA>lnG`> zf)p1kFOwG4K4gWyY!2r*=si7Yi*Ob-mNxUGNfhsqLn-Qc>}d{eBvTTyv5BOOT(W|| zWcBEI>0Ga|l63}ssS8OS#tN~nA!Rx9amgp4Q^p5xb5IGTjv4L>Adtv5myD7RIp?8M z$K~%*$t)r^YmpzDBkfdN?pDV@a54|)#WG;h$~G{97TM$y4&vA!u4|$fvDFCPB_Vc? ziBSVMZ{D`er=CBT9M;1ukvK^sXw@NKk_36!3S>E}g`#LmmhCgXpRI4|z zJ^gc7G;{k~8f?(2tg4FgAo)~CLX7c~j<_9=)TJ2AogSANXKdR_+_7m9zC+lL@@hwwE_Pa& zo5>N6FXqC=x#Ns<>rxiAk~n>FAOq=|y$njQx}abmjL4y|Go0tB{3|)d zXenL2%1aI9s-=*%k*#JeB=-|z%VilT22OVSxnoc(e7){HjNF<6ls&&b>dA%{H=dd)V%AtW%XNG~o?|QG;pHF#eMfxz(n7Zz zoKCq2&9&8r(~qSyP;7=qjA5fz+iw`%yCp#(K_}ghxji#Tl9*vgK-(;VK=T^_6Z-o8 zwXH9GvuRLiqROa+ytxsO<8a;rkQ}b!wy3*~6h48J3O?nuZP$;Nx} z{b{D<=Ylg50v*E!$lA=kN7PnHb1 zW#A|S__L3v6p_VoHr2U_eAtn;%mCh?ki}K8_elefYK=s#ad97(!rnNYb}=OG9-pmJ zh0KUv@_qK!%2-czBP?@q<*q-8iQs3ZKghC@-bh~B;x8&|Sj=-Y6C{w&COKs*{3P_} zy*fWES;uwcxszziO}X(pK4EU-!yEGs z6AM_?10Ypa2bMjKMtWnQ=Zb;kcJn2gRhG<7?b^ai3p8xoaCQR>r+JvnPRyJRLtDN1m&aWzc|m=9qMT#ky93_6E(XtVfHex z0F#`YHhnqIYK1Q03S@1ttY8xxxEoJ@%lcNzGHn@7I;$c}$acmjiJlvjk(DG_ij(R) z1IMjL46Snmy~FvAQI#b{P)d$5$I_>|xp-XU1`U=)3-Y#qJQ~VLq_nZMM*&>Q%qNqE z3(p*JgV*pL^|EavvXmm$#fv!Pno$bQW05i?GQRD@@Z<3uQ}@Ma3618Iykk$sXf#lbm)UItdWT1lNiSY@NvhbEK?AWfbg!~Mo5!yCxe5KNAmjAmn_ju z3I^RWDZ~K^g^Z89NbErbeJZ?y-Nm)J%yPMAibVb_3=()9`+HVON>)6%xi(q4HsM)i zb-0#IxNwJRw^7t~H5@->b-A@NNYh9ann8tNPk&#=nQ;on&e2CIqbM$3Kv=dpJ-Xu~ z+N4XEVU9QQp`JtXFeIxgx6}I7s*SNqNK%qYK7TB-#fi$2rBk48Kd)0zpoZS*V}?TE zhZ23zNaH6Q5=Z&wtVc9)#?oB|21B=ZCmHN%Bb)tQwDH2PGydeH!I-aXj>O}ktmLn4 z29~{S%w-XL!t2x@dX4s9Glbm9vvj-1Bc4B{Nf`SxT*gYQ zzDn(XDVzh?kO(AGojYubl{Lya-I&UPSfL9)%w8?b(eglEa0xg$^as|f{hYYE-!059 zJRFE$ZooP!k%9^9p1jjUQvkBA##Y3OB)g++#A6#s&M}@Fr_@!2jxj8sZfmG~zEUT& zA()lQ92^a;$2rC_dFfouw9a3K;dLazcO$3S+7Q2IYjTn-gO)qnh6G>$JA>*dCM}UK z+8N5Q-d_NaM?Z+-q`kSG{gyT{Ovh@XTuRDSzlpbCWI_xAexA4+j%D=f>tF)la8?oQ?%&%azy zt#NX)qM0@%jpW{O9EC?rf!`f@?rKP$NaDGOxM2}p%FJ1qk=NL znnP^Y4Jsh{)cmTdcqDY>kTdQpL(7(Hdtr63OAbxe@0m#S9X~pr1%~0!CA@L@J9e?S z^2?5-u{;CR05~`u%~X+=UouvefQ{rG-(C|f8hB%!edvuOJF(Ndv;o}kc*pBir%Qz#WgmF%{`NW!{&Z9y$xx}5+^3v6cU*28+0N`B66`hwm8mua!Bew&M9LDWYAm{Sg)pCp@-_M4v}S=rB*AXSbsyzmqr2*yutYW20ujSIA~iCDid#x}AkJ#)_;wWulkbKgk5gcTm!=TH0R7@Vo8RMH| zj^ztXNeZNX2fa(=BYE;WnX>_nOl)wc`Byx-)~tsPX$@F2Jnq@OSjo(f5RI|hjN=DB zrki)>ytcs?YPsDbg&>kT1NqgfX%!e+`9#I#s53DjjCS-bZ=%aW~a1e0Az_Y1lc zDyqgo#`fq4#z(I{l|1rs+_j-e8Rb%mZyYZyE4pTOR^6Nc0N{5gJn>RKe9k~^=MMnmNBgOErg>Bm~ky^+*0YkPPvW^RxYWSH~^pW*|L zqShwYMaH-ZvRP-I+D+`Rh@6FBMtsUz|sag#u&2m{vYQxd|0fovk}O( zRdT>H1CVpiAmn2s>C&^2t*zKE*@W_dRi#XB5%b6LuG&((QLJ2SNe`PaHxf%c(lo!k zl!DC6bCOSTbNbVxjrSXwWVw(_5mpoYrDM+nrd0m`jYBQtKZKt=L6{Qr6@BAUrZWn;`Pv&Q>R>Y>+|D033`S z#8zyoLrovrW)Ctd+$?gH3{)Hwj0}O_{3`wK){)^xWr>)UVe+w$8P0lx$7+h;SgZwJ z*EgVVl1W?zkw_a(I_JJ~$j7BcNc0?^N`<9Wklo5;j1`PLa52ic>4G`@YEx21H4s8s zFCBBfSB19uR>fjFFaRVBXQAhlf_-WC7jh3Jq>Iat7BWCcI3td{eR=g1D_%(y%(A3cLr?a)426jB;Qz~^xTJa_zRBPxxp43>l~y<9wzoM0*BIyAR2K;`i|r82Z1)ks%N$2*Fd*O-1CVk%<2m=uXvMp2$O@() z`cVua<|1iT-tGkh4j8DZVm1$tYk~%0H`T>*e?@MNDrHZl1C!W#`t8O1*Srv-{eLY7%&YFC-S;URzK(4OH zyeM!^82a(k{{XLA3vV(ckO;T3ZFE`WDy%b-bJy`^oRt;3I)V>v#Yj-TU7Z7zJMT^=v92-wT!Fbu3tGCgX;tTs^F-N$LH zM-$~?U$TiUmNC@4fq+w-0024N+Z9qTHdc{j-z}h(yqF^gDteA{j1qqiYkE^`*6vA; zk_&rTl3SEXAs}p)V18Ea-k^@Z(w!`;mV0+#Qa#8{7_mLi*EN1fkV-zEJ5RDT%=p|u{5ZvI>LhdXGP1_&G`9lk?)%NPRZDrCl!O9K z*w>=ul1b`GZ5y-9B%v#>)R8dV#n5BH8va&y}` z7zePbvLwO8-dh1IMUB}i(S|4P;2eT6o^jNDYZo{pqLY-7CzlM7E4C%XyQGd|v;sO~ z+#C>nMOjJZl2%f2U7=Y1Tl+1cKxJI(8eL zX^3egZ|^n$8P7Zc%}k*y=+3WV`7TzPXNoBj7gk>}S|UMaR_HkEkABrSYo!b&!MG?4 ziIrf-@$1`~g4lU-2^hxPiTMcyKBxch5}CbJ$h2- z8>DbUTu4~m!UH2`fshVz2;`pFs`1APd1-MRk%g1Yjih#B8<2VQIXoVmdQz2vV2*dp z3nY!?#TGCW8~{Bz^{%GuigHPpo_XRIFviSn)>zr&VpMJb;k^z65D&Q(PA@&JE@o&9 zK5^QUxB+BrNF7*q2fe^7s~r9vT+IfRWNJJ9AeM*G>u1~Z-xa&c0iMj2$>WOa>>0NNA37##J_ zdZXoCt<+aPYZp=?uaaCc$>wJgGacA%!2R3~N4UoHq&Eu{ZBC1H(%N}_?qv=%>BpEiT zB#noK9C}lhS*~t2;S$yGJe1=jJ&*qYTBn-YLly?W5b&|#n{9SRqH#3#av+F3+YHF4 zySFnc;05W=^8D%2T{2H06UBK7D9o`(wLw35K_e}+cRlmznvB`(OPM5fXkv*~_8gUb z_0Ohp(xZf32|TBXnh=Y?&R<~ z^O}jIh%{2c1lH>ks4-12b~1N705Or%^{f6$Mxo_%4(SRd%yBLk7{LRfnEBImdsAjPfzLoO>JapUM(UvxRsbgZ4eQ}?5?0~ z{Ai7t7%ZYYctd{vcHB-gj@dm=QPZETR}tPt4Ew}OZ#xw(^OF3W;Bk<1o`h$zt*zmXs&dV z(1|9AQtT<0Vr>vC(3shVGB`e?6;f5%0ssWkd25KtU}GKrok{-y_0{-6ONW+qR*kMa z)|x}+2Vvd4^TrRLsdlTAa*;t2mv1s~a#^r?^N&uRg0yhCij>m>XXO6!Bq<<|5wXwB z*ZK6S^FsuhcoW=M*Od#IKhBoHZR8BkG*7rT=2?}bG6T-x*qnF8Njk(-voLlc zcl62n0!BUSTRu}bwx-IlUgQIE$uE!Vq8hUby+sBUidiR`-*6q z<=$xH+aoh7`HG(|2fae}){Ai)-pM*FQl0)pCG)}e9A_NXRCN`e|4Md{sx(KE%ZKYHt615U}2I?tQhCE za&gZ;;wh(pLs(iutWuc+IW5NJM+a}^QM8S@yu<=FCvQyS*W2)^;<@`Ovb1eCnI>K5 zkh?Q6&Ph2vO-1FIZq;Lfrg=89TSVWyZoNHo&{ZiUZqr7S#TCRR@FaW?n@|kk{=KT4 z%&-qM`Jp4T+);RDAoR{Kq>g@UbgFR7k=!-2POmP&#soh%IoroxI%m{Xg_7Y;*j6@K z$Z6ZnJdAf3>b)v?qGdQraXgC*ts#xu zdq!Nd2?tIO03JuTYI~%yD!7i)SOd46H1|arLE(0)#M#{bUw76?EgJ0PoRUZ@ka_Gu=xWJGzjDTM@iT@eVE^5oB6IzN#tOK$|tV;}l9 zNm&vwSd?FzZWx^4j-!LlDCUwg_piAU#McmRZS1keyNE%!uT0=^nu1L@c?x{V1*w1a z^I=2r&rJ01^%Urq<%`KY#vSqPmLUmQ2c}0%8cF<#VKKt<$M$H}J8N~6h}CnG$82-Q zxvVDS&FMx-gm76QwJ=8jiV<7jPcK{R+83P zccc=SnkqS@+Ou;x<}k{Pt%cs$K_c?&zn>>rFC($TZryvz-U89 z{;jW8XxV@ph+qKZ=KyxV$?Hsw=R}pHk&@Op&QVn5bL;rja6R12*3-4Ikz`i4`FxcF zsL5h^>CIenr^-*V+eOYpV})g0s5uDDfOz%iimxmy91z6UbS}I@WG#<}LFRSXv^+*B2sW`9{<&fx9>zI*c6i>+M!nOOVU9TpL-Lptn@PVt!IG zqviy5KEH)l7n3ZO?PiYqO0j}u46OLTJ8_2mYg%FEMFU!0+fS$n0~xLD*<@I2v#Zz@!uT{ z2?M0E!uLW+rckpe0IJ9d$W{lH<2m~Et1gm3<`XQB0DyULw2HwSzB^!?@%q+=3z@yd zGqt!#A&~8b2`I0^_3S%RTir=B`7Dwsgn5!FQWTB`bMM7PZEYGmNZVdXah&uE)3>ET z<*Pinw^uQe$vb`hz#a!6V4P>^#RjUy+3nT*yR#{_SCE`WN~lwiKp^J>IOdux%E+;( z63@GBtYJuQdk#)>{VCDT7+k|Lx;!!YeaPzXs%fR?; zy(?Ix(X3U8E(nfvSV_YwnbVS+hI!9igVXA232tVEag}VH*a@s2#fybMMIXtsk?Di0mcQ_p|bHJ@`H=CrepJ6m^#BGCw=D$}<)$>>fofyOcFYBgA4 znJwW792jgY18GhP0~`)|WKuoT!L{T_QYb<4rsa;))VHQGcpZj&(o$$2H$ugn@8vI+ z`y`Iw>{0<%Z$rl;)E+2bIaTDE;s~WvAZvKsNTr5wz>I6%)z8D8d^&Gy9!vDyC4*^vm` zIqH8baqB`GX(N^}t-Eg(oC2KHTFTy(;?OMdZ&M^94x0VQ@;~Ks|B@ z6*}DNjU5v_4i`x-5=m~Y?b17)-b93k7(D^!!Q~rrR8723WB?anl2@)|uxk+uN%%W?1C&-)=Fx(C0WKoYh3AQBo$l zax~K#!hIOjMqv~Kq@s>W^# z#Ii?iYZ=?H@HqAd89jd*sUj$!$%0q8o!l%b6b3a>oPY*Sa0mpBr=M!8q+6jF$IPa& z#@9q7k1%;ZcG8>z<+GE)I0K9fRof_$TH@wwgKio325B)GfKTxAw2tQ)=9xXU)v82g zh{tfVF?C^rnESkYj(-}n0&aQku6DiDn_e)?3o*~}4tn#}xa!twK?Iw%#JhKn7+vOh zTIZDH*=~!r=D9J9nPm|| zpfr~ffTfuC_WWw9ZIfd_ZRS}eWoyLbl^hkwILQ8$3|D?_(k!?^GM1H?1quNpgWO{W zC)Ttk5=A3HW~I_V%F5s~d7K=Mha0nucH+8W%-*LYpyJBneJ&Ye(yni8;ai#4$b#Z^ zSsk)CT=ITwU=La*vioD8xGbJr?8_=S0F3ZS>B#2?`c{e7wWNnwvD0JHVAFM-Hajg~ zYC1Ap+-&)`8)>&GiHMd@nRy>6CxKNZ50P184#VRqlEQ-J^uvyF&O}yn5h&agOIODBmqdsJE)Nba;b-6H*FP&(^8U#8I{B-8;-d^1)%a9u9x4Mw2+Vg)T&KENWkLQ-+u?P5|*h z4!^^L#&UluxoaiHpwBhTrfH>BFL1}^W$FnB_`OK$TRwJ~bep+K-K2K9SqxU;Krt3j zS--pof2pa~?iBL4j#%1ND7@g2o_%r+S8G(7ZHQ!T+p(MmUEQ(Qo_f>X&dS~)7ChME zM*Z2!?LC5(IpA_V$LGx@D6`O|P7-CvrdgohBuQed_v9S z@RE%jxn^*38@hwWbH-1#C9=3P$RqO0%FVOP`>J~nZoi#dv$XT0b`I^bZPwsE)>H4t zBd;IfTGO19U5r%K*r?30M;gGsYRR=xTNqG!_4Mp1o^7+pw)XMNZX}vXB%P!(EGh>p z$-oVqW0S`n4LS&=OUvua(vi&~D;qe7EQ^8@fzUQOo_p2kL@^@H>Xy@95SsxcNZgP} zB>dPUagGP$UCDD1&Z5l8?WB}jD=~mbWMYuGF|>H-NzXpn$^5Hla)@G^QG&%`XaKNp z?6rylBH)jecB`mmB(TZON#?7|6|@U9N_@{P+G}X$AeE4To_duhqMn(m*7C~onH?VD zRomp-#sN}(hl(5-4x?g36YXLW@kMZOID8gdk}x`VKc}TK^38?Gkz|v}fFCT0HpwFn znHk0i;~lE?ye=$6N(_?4Gc!u-xpuLA?O zKD79Y+q^6$G4IY&EE0N-e=6FHLbLSdNJK6UNiVq?yU`{$UKR> zw%aP;GjsU!jz0lIN}=uNmR2%9-c!`^pKtT|)7=tj1iouW6i1^1PFtVrU2&6fG^+@! z1anL+?q-Q3mBewgFu^X~nD#%1J!)vB7pT5;5wj>9upcXR&p%EooHt6B1!H`}v6WTO zoHj9%Mls3A9^J-j%+c8A%8ny6Ag|h9Pu?$>y$X;3A2tX+)hcY{aCusiZ$QU5xU}SOB)-jz#zFcv6a=R~?J;a5T zhI71(o^j{~c=xLlvqKPjQq2{_tkFquM&*+q!Ui&=^MlC9sZX15*wqmT;$JJx7a*L% zL2UJ=O4l+3jb*pq6yZ@sW2Zdv$j5r8X?uD0c_NZD^T1y&>A~Hc5JoZq2RZ56>MGs7 zKq?#L1-BFf0As1oIPJ%%s4Y2MreY>i@?6O0&QK7@rB$))0VAyj&MDM_?FrlSKF|nY zbB=St=uf>%u~;~XaxC2$(3aZgrx@#ibI%k{9Iq)@B?2}-c3ASvKRyjoI@GMmt%Us& zCW`9v{Ca+v$uij|SQKpgSU=Rlm=Lu4imJ52Hz|-T>2LjclTo@0sofNLgKq?N&S%+k!Fe=~v9r%~sO5lOTCF8+&PteGJH1fgK3s zat}H76?WXTj&0zU%k4m{h6!R>F^*KSw*(vzGwD>8b$>9;wh#ktiXuq-=^(k4*&|j` z$!^UgjetnxWc2END!HO^Cp68UBua*6WzX;@ zG@Ov=?JeYiT1&_zxkqN&H!jdQ8OX+aah^xgqw^d|6w0Vh(p6+oMmp!}Dv^>V2g-fo zWD6((g9hq0_CHZkCD@!5jhVO6`T&u6o+ceGxIm6;CMBdfhJi| zVkS#z8atH);5R>TkGwzH9sZSEw>FQu%?Vkfg5D*O7zNt+P#H&DlixfJDJ~;;9b*u% zEAtO95X__kGwgc)G>vH9X_XnD1Y;lt&*R4xc4;*wh)Cs9C<_~jlnu0{rjo3OLuw|?8lV$?RF7t)bT7N$n3|U zE7t(a}JS?dkOwAPRbmNJlqZz^1v$-%<$oO|*5)`p-W zxfe3;l`mj1jG}H?J#u||cIPM3vO&8tl~+GD&nh%uEzt`VW0lKekTdJklisyHK?s#) zR+b3VtO~<(bK5??^-YY6IduTXac%^Fk`-G&-Da%k@T$zWJzbZ1*6Bx zr9c~q!NL7MO05;L8Ink4Y{eO6a50wT5J#xvgH;(Mja4;r(T3&$G}fyei3yBKw+yQw zX3he}d0~KZz;ThDqM?fRS){saveGd|W0Sd*W~Q1cT&t_cCRBNjK3q4aJXL2BTci?2 z5SXpPi;yJ>S#$GX;Dg5_x93FDW?K_D7a~a8&y6+>(5#+VP&@JJIu7});tN3l-gdla z$_%(WK>X^=QWug$mL<6Y=oqEtaJ`ER^&Xt_gY=r@OC{6EY9eUhbx7fqfw&NH!5{

G;&F-cd&KqiiwTy~zZQ{{T_eptnf{ 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

Qu#kFgQzct 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 z zN4I`!KKef@0ITvWF1=G}3UEhJoDh3@(#Ir|$T1Yw%=ZoZtAyIBqk$mdY zTeQhKWp`Z2%-C<4c9VnY^r<9<;@RSOH^~&TZk!hZnD=6RNCU5>XC2L)BICJ#{bG=I zDGIFd+sZ?9?oJPEW~f|S%M!3?#_i0>A^YK51asF1kI>SM^P{9CVG|>H_wo=@7{MoV zW1N4xlg>NUE1^G`4XhCWUuylKC3cc$JveR$JODifbn{=S$y4DbmMf`|S%g5hMoc#4 zKBI$>M^EvoNj7d7Cu@jeVX{eJ3dH1Y%8dSBtwRD%i5v?ot#P%PJmmyur#o?0u4R_x z8Y_5EJkP_2V5l?CBRD?C+nS1xQh8-4mR4JLC8Jr|CmB{T7~9OxaB@c-k4`E-G)D3O zxdE4ZE*K8K;ZRL+B1wGe8JlY6;m^v_%Nu5KBDVtcb-0mljk(_hM^r^ty5;=e4-AOw@48eygNbSfR z_MzTp2_!{B6TonKRPf6Mxsg7{_L-$(*H1O;CL`U*LxKUvVh=%B$tI45_AOzGqvI^f zKYF>`PeY#E_02&nKWtf8vnjVttYeU=Zg4`7diT#Aden?o84$o`hAC9+37Hrv;|I_l zhdqfkhZ5ad++BooavAqJGI1E}2lLOVHPcRUu`&0g%{ir3c`e#9(lkM0WK75uk7rYC0EkB<#1dLoJA$8bPHF|-%BFXfW%ElUN}HLB1Du@aumE)H)4Wz?ZUw?Q zJcU(gR47&*GCH0IQQo$a=0``e=IUx}+GM*Ce(4+pM)|ODoPc|0y*5N?cRXMgA&L;( z5Nafv2_-ht-QU}{lvyK=+ldr*V!&-YkAA#yL|dc#Mb2gNbk%Lvz=blmTq!(cj)d{+ z&2Ti)%{V);A&x|5xtWe&+Fxp9dJaCgsiKnPO47?9K^!a>qNxp>=jcD3Wy7m~Xvp4t z4{HPt-@BSX&bTC?z&OD?nj5y!~oV zJNItPWFwvDX~-D*3WhYyay7YGC015!zae|%^%X4ZDU}bLh^|A*=t10e^yeK91p6Oq z+6km5a+^tMd1CJs&CCV|Rhl%jB}WM}Ztn%d?&eL3TbR-KvH8=2E=k~TV! zI0W@LspYsAfu=cZM5@TD7Z^V-03H2*`t@GsNaVL=K@4vc-ea&urlF*Vma~QX!S`8{J{N zu_~R4Lv%Pj{tc75?h5RtNS8cJHIZWa<4V;doZ9bK5Pa&h4 z8+qQ)K^gOwUCPoBIof&IteAIi$7xfws7x3z6aw8@*$o(p?n z46QfHV`5CpjipCHj-2;2(F{)ynI_|J6nTklW86~*gSUWs^r}+LcpCZoKI@;lA8-AL0qZmIl;)NqGh#tC)@kL$`oS&=REcI6v-~GOT-mK zzFab3soGe#a($0M)AOvUMl!kG8Mh8n#Lz`?m~IrLF~X(@ZEjjNRv?3t2qk@w^Qy|1 zCSs~{ZV>H^0ha0r{{ZWMjaRptIiBTF=4k^Q5*USS+>UZY}? zqK%BI1fRZw64MCTN{r-W`yX0(WR?iwduH?HU?ND0wq(yB6M}szwDxTUtT#|y2)x&5 z-W12p9zU1Tq1aLwjLYV$$2B+ftyZa#9rZXACudj9}g&~M(YyeO&j z;iMq&NF7h}srRD%#X0jcI_4{HDrja8G*e0%SKd}eU^pP>h8>9MikWu#le|IQ;ZNSm zT{pQkV7~T%w0=;r}vRaL1@<;5<96q2PZvh)KbEQfXR+`T(ad^qa5Sd^{p<} z@-dS|K@OsqkjEjPWYdONgRogM%HeuvAN^{%Zwp+>D$2fn(ldRUJ9K7c$>3wIJ^rSg zsAXG%#O_Bt1BK6H@4*8SR^7k|gra+GJKh z17U|4`V;z7UEV2FKm#n8^PiGQ@1H~4@T&J_MuyTwQ5(k+`Oe%ljnos{KTLfpx?aDS z-f}+2LFA}H!KBU)KjZnirFBOH47HI#WJEp|0pvdo42!?}Y@$UL#P3%9uS{{Z#XYq-o`>f$>O z%{XjekMqqkX=0TRGArBMDzIWk;74!qtD|M8-t4lW3b~9k636^Af_ic3&345mj%t!= zZ>d{kZwT3dBr3%v8?f2y`BkwXTg!ck5<h(N zssYFy`**7<%EnnG&AT?$QdsR+)Z_pU13k#(jCu;^sNmb~WeMHxO?ZM!jLo+g9z%>M zR`;x;*2{VlB4fFX@7)~41CT~pe~5MKo|U6J#uv+t)J$V(RLa>=jGS}Sb>r|AN@-*` zjKa>~E+vi?464KeGCA9xx%K+jGu-Qrku6%5-#miqJFoy`mhK?TtT@^b4W&*=Is7`) zrGfzK4TZhEnnyX2ZLO0rscz&GoMdn_^!91BNX&~0k{y?HU}NPSdHPnS@?mJ)POceR zGjA+t%1H+=xDv=fBLfGVf;rBRx*@x>DMGi}Br;0!%NLn2bPKjY#sTU^Fmie1`(|rY zWJw5ySyiJZ;ewVif_nQ5{{S&hA?CeXVJgPHUf@XqSo4w2IpU*rb_|oc!*0}01 zV<*}fKYN7TBw*!1;|H-g9Q||Foji$ca`zL(@=Cj0sKSNE-hZb8tCCQ@q{>Z5gj+)* zLa2&_rsq`1Rs)a*cn9lGytPu_B&ZR}waIk>l=~igWA*%M&$yW)M`ILmx5~I7kdS)y z1auhVlb+S6V})Xgjk%Dd>&mbjbM@^>$+hNXc_cE`plC#JFAB}LV;ixaYJ1zQ$rQh5 zJEK#wa6VZWdiE!goYYXQlo87QK$huDj}zP`Wwk=bazsJK)*(sAJm3rgRh~`n6}&PA zlLfrJrzbf%&-v+CyWF0Cc$QB!)+od=vM}8!nTKJ!jNoTIJNEBTOXfMcjBS=y#EB$~ zRK};MALp%E`%S&QzWJRl0+J&tfth6Qlg@oH#twaJGUHHzS~-~`TZ{P&a6>%J87qwB z58@zYg8K~jtAvtTn#F6eJ*UXmf>zz-+N%j0D!X!WGt-QW@#$AA;U%<{=690CqA$vvrq_mHTH{iBev z4;*r`$s}hgRSM%7&T@SS>S?kew?#;VYSx9CF*KvhD#MUlf_ij5zV$aQ5{zD`ttIj@ zd0#&0HmRB8+9YGo1Gx9;&s>97?Pfq@f<*bAGR-WKhF!$=9eDn=S{NeV^a@fuXJ%?U{ny(Jq=mf&* zPdCkyIm9wymmIKSLF1@6=jmC_o!*C^HzzH~>>lDtZIPK1q^md&gN3l}u|U zC*2v45;*J_5s$AKtvOBUDL;sCdvPH0ZYEJ0HtAuAv}BGCnB5eqQt|bntFmPFYeYmNetkIy7E$nwTR!_WCdt~6}nuIYjKjxyCf0Uu^7j<)|nBzmIEwzE?mUhV~nmD zyJst&F^)ZX?ORinujEuB?XZh+KE*&nu>n;^6_+3VZuI#){{Sn>+@5R)aywwLUu<#7 zsRVO`iRXqnE>%>iL;$hrj01z5_wQ8$N)~A&jG=-R5TorMC_ORAqBVJ?YZ|78%@lAX zQHQvZq+QI$M$Y1S=Q$mFeian3DKfM`GZVSvWh$)WjPch11D{&D*LQaR04g=2+%?A7 z{L4WwD~>qe9((gs%F&`@5gUan*jz5+=hN{0D`1nAwjhc%i)+Ul!6cx4rb(nMtb1T~ zsb*!7q*(c9^7FC7GaQbbanJt%U*0>Z9c^S+WmY}o!x8z6R95nfduZhr_XyGF4&`$< z2OxIjeFrp~vNLK@=v7nYT^ZxJon%SWHK;``GUKT@;QC^&q%+L-61~mZ%Xt)wC=RT# zgUDl%xlZAXgPwX+t0kLEk^)vlP0}QQC=HXq=bkwyj{cP+`6LjGAdhzGq*ptb5_u=L zTyfY|UeO~q%-ErsZlUwyVDmz|N6pI-o;}Y7tXkU7J-8OrERhLc&Q%97kVh;?0~t6N zC!eiYVYz1Vjt1T2a#dHL=hCT1ZFL)ht^3GGX(Co9E&WADx0hpja&|2Z_PadEWB&kH z#%+nm9l8p)Z#)tR<%i6~@wdq;va+{q?&k+5^7>UjG3ATS@|BB8^A9kBS3O7J#YZjV zi8PB01(ZZl$`OTZ@Od?~QlCvroH=(UlHNelHN-m>Sz}m&70TosvFVjK7#`xPLZ;#5 ziqtz8u6(&=QyT>fl6P)AgN?jo^T(*UBKfvTvXe30^18n7n4SiGLF4eM?LXN^mn?CK z1f$JX1BM+K{v)roOQjQ)#i@CcTF?EPHlroPGs(UXw(OIL&i6@hEY7!@L<;RXN zpbj!lPJMjn4*XqY3FIxBVc@$V+$V+SM-Nf_fbLTP82mPn!=WQwaaX_X4y zGmt)RKAeM^xp0gZ_Ywq) zk$z}HDDwVqFoW3isG(bSp3uv7?xOeimgXf9s*rL^6T2Yej1ktavc$J=$s4SKGR$pu zhF!yzBpwJPbo%kqsZ6j3X=RP0ECUq>=2rgz_14mlDke2u^)%QSCzeFo#swQ${$qpF zA6!;zeXWhhn{1n$=X_-DEIA!|@y30s(YTTr?aDsc04zyRRhyh-9=N2A?MmB+n3++& zc^O9LJpLTj#aL>xi`c0J?crO95J41ELdhAtw=+i@6On=Uh7UPX4=0{YO9WR?7~e68 z5kS~R;<@J|J&EJ+KDA=*@u4Xceo{u0sZvxIG9G%KaqZfu#c_ReCCuu;Vn$*lVaWvd z=Q;F0*A(S@3!YPz%Timd(S>ecx=BRRX5|XBGGK53z#|0ma(E-tnN&v@nZT z9nHPeZ*iMrBx=S002@F6Wl728lafYpM9@QVW|GLUOO;kkbMtlReJG8(GdWUC5-}1X zX<|p(11xNJ51`5IQra74ns)n25F#anNLiE-z##U|ALC7r<(5g|Q1QBvZwmu}d-e3@ ztCd4E_R&SCv;}^?q8?nc)1NHoAixiVY z9a7@rNYG~8aKbU3gRtc1KK0WL8Y&M`0#;}iS=1R~VHidSYLVZk%no|}d(^sIaYb&n z!NhV)J8p(N?orNp?V5Z>6-J8Ll2Vc}xPocRGO1!)u1I0d2jRwPR&B7f@!O@tJ;@Qr zAu1Vq5^>xNoOH+;qD|Q8jI=avpleH*3cPPKN~O{V5-3x^0IqTeT$-hMVP$c36~y+@ zTsFe1B$0+I^Jh6cj)SMAOKGLUrb8sqMQH`Rfb2_YQDib4<0uYsfsFk znrn-NES7Ob8b*-tBT?L(bUn{X!XFVXQBQKC!)4@7g_)=GLc|kmApkLT%KP-^DB)wEFiah}phR_5o;^Zx*OZps3%=jP5%eK_?# zl_k0*!X#|pXPB@0v4AkX{W%|vTawxtA#iP@A!JczkwybxamXF>O^$eDm`(OsrD;@! zY>zK+^cefY*WQONWN8(2K@1l1&n2|hcefJDZ<||-EkH*U5_QY2GRxZo9FTenn535W z(c7y;Cqmmi#a-O>`LUiz&OQGCIP}+^3*!?hXV}VRkcGhQ)B1W?=5-HTw-NA`AiRe91f%47s&1K$AtwEMBTNu&%S`^r*0l@aml zla94|ZkIlKNo4TEuCm=e)tO28b_|>xHtoj%jC)mfjxwtj;T^;7V>>H6U}TPVgWvxE ztyfMl)Z=n1MKjzikfq~B&_D!MkmW;3)H~#S*j#`Vj(VOkL7E{0W?lQ`J7#mVDIM5% z^u97|u5~e-ceqVJ>&4kc`aPGsU@7p5zP@^cANhO%sia z(-QE!HmMo&WCBNY1(bEl=ci7ipUl-%op6mNODSYana24PWP-;T;Nv_~Zany=l1p9D z5}&yb&f)a>_CB;j6lN%zNf155Fo?)T8bCJ?J^TGD8CcF*M6$SMhzaAkLmw|19n3-L z&JXA5OE?!EShs)QdF(vI!vF{M1XWpW=fqOOCfS1i`9tjhcftBrg{;=eh~qLj-}0Fd z0@%(^Q~6gjoSQIGlVcQ17#7KGbSEX7XW7`6Q|Lx1lItzv%Z7 zO3iRrobDMLPaQGP0(doIY1kLG`%LQ;vSh;*!>De4^KI$?CjzP&rJKlGOJi*xnBO=; zt0O7vp8R9;NNo135gC)~d^LlS%?W8rc9}wtxbe zkMIH1<0B`h*19Rux2e69cM@pVd>Do_wkw_MAtb5lIp=}={p&eVV7ZjTBf^aA(THJI z-bmmb-oOmzv>pYOr7bDmueD>2;3~9dJMh4tn;dXC{3@)TTo$WlmhA*>_eAp+m54kA z{{VpGGv?a6Uk?E(nk-Oc>;iZxY*!Iz#o^MhrUH)J*BKy3_r9b za$#SyOEiUAX$dEwByPq@#s?nQt!Zuyi6ml0Vj}q!e~EGH>+My_0E(pp831KZCH7BHvE3*do{263J} zsUjX$>4Ue})+OFp9J8F~o-=`u$kauyAckd#53@f>9x>(>{c-;Q*Y~8gX6n+8<$tr= z3$e0o!Igu_kQagU1D|hdsH?nZaq@oEgBH<-_x_cl(9I>JY5SPr{vj)cm5CWn4_x)g z_VubHG$^|l%OTmOTn1G>gZ}`pRqWu-X~IfG=GW~laOhSrs+&&ILmZ5OjES&?2RFlhjKKw`=yBy#E4ss4ZI*r=X65DLJ-zeMn&&=P4 zeAU?@Mx3u}lp|>5NvDy{^<^pxZ7wo%S`bcQe9IdMu4HCm$Wa$=xgd=7sxVB>jUTn>?q$e|TZot|s5gE_=6-=xdXK}sT`z9Ps=vF; zs#vikZaw(V`4tREB3M#5QUoDZ+R_C1V_e`U&VEoh0H6N3aLoac2I(VW$c$qjFbDMO z+NIfUWh!?pjOJ97!XI>tZt^fG<^T&p^u7bh%I9#w&mPq+!sZt80!bnw_xXYE$6Ow2 zC5Gzjb-7D8Enr6SBuGq-%zucIK^%+_IN%=msqL8Ctj1ZAaRQ&8VO1=6`tk2s`<;v( zCbcM9+Q%bKmoe;(q*)<`GJLq(-?;;}ezdYS=8(lCN?mXSutv zk*h>hqlMlWfI%4SdsV4W=VVG{kzH`=Lo{pHk)OIqBDIXJL}fU#qg$|8oX8&o_oZ{! zG+Zf$;K)ewkSL3CkC+bF=~Kv(Mzf@i@;ZFQNXT)|e#fOH#BC%tf;e5k{{UJ80LLS@ zp{8o2?n4wdfXcye9QlAKBs8A>zMT71ayE8(a2Y@8jlSP9M(Kgr5`B35>R&1oY9@fW zj@`Vrc$lyx91_PJLF11~bZW83I|4+$Q*0ryRO5_v@7{x|oRSN-mL-9u6_i zanCsFD$84}5nQMRm5)^bvEr$}mS9E7$Yc%W#L_0O{HR^nBWo3Z@h1fP;PSDzYg6`N|Ge=&yupjWQIW3 zws^}%ry)rlvOxg*5lE~fieV&V!)p?NImnMZFg@^ma{5tNJX)4-TwD$D|3!B$UO7g z@uxXilDKgyw%2IJ0mqd2Mtq5Xd9jN{3;jjeo;u%wDe8xBbzE)P93^d@+1W|?hWrcLq6s~!PXjgCHN zz{@T;!01J3z#26Ri3D-VR7PbhhCKqP&gCO$CqGc?1$LAS{Rfo*lReJHpat2S~PCw{r<`!UP zW?QvUxCS{q9N>)i9<zjY5{oRc%Fy|VZvxG` z&zP1Wa8IZ|k7|NOxsgN4r_46SITe8UmvK4okErZxV%pu7=6U95+;0IRc@{-g$7~V^ z>UhsutYh-au?~?m;iGmK+{dW)#R*vIjdg902eplhKK}rmhE<3~m1bfvRQmCs%BL(R ziX@d(Gf5&eM>tdm0QwC6d~?#KwuQ~StrfgCS0^oRX?Jqa!rrV{bC5DX9Zm;&8YqNG)KJJBgA`Z%tM*0nlme{4b;0%b z71!-KjGe3o{lxD0*q0Hm=$Pjx-mFJFGRYFNTwGhCf;WL0$u4lsP zmMAW);$pH!cf6aB?Es&;*de;-JoKh%;odn`+R)s{WLFc!36Ky^$^he>jPag6xrgxs z_mD{&n~Rvz-PS1OSB}vnG5`t58=IawbNSV&rrjWQ+YlhJj$l{JTpz>p{Vz_JB zBns1&Si`qJj(zGKN_&Xf&&_7IiWthp8%>zjERsSFLY$I)^Z3?W@Nz}drO#qUv%d0? zyw`Y)3L=5mXpK+J#~t&W`}@+PT?4)aiJDXq%2qO^alvDblFB&;1fQ3n=~}9h?pvhN)fA;L%V!tZ zZ(_QR*pVEu%o$9BJC{G+3>XpW4QyM6nkEVhJg|J`6NZhCOfMviWE1O(s}d?BTgZ_~ z=eWwt7}~pf91LWR4tkT%dRu6?B`)Ef*4>{o!UjupVVq|Gj9~ORs=ditiyhR=e2aFt z`xqIQ?I;kmfF8<7$fdo4-tyT9g9@sl-Zdellhgg+I_Codn_`a8v+ZdjNn3LaaJj(b zWDb9wRf;>6xVWAhtE&K8ZN|!2UE0!aSWP#9wo;`&onkBblhcVqpJQK@pcCoPE426DE z!!CUY$RoHlI@_@*Lr3PF+h&mq0h7STaqU(F8HE-W63pO!^`sk^oMA%X9OrgO#IsE=lB*U>4b_MlB~JsMpnWR9Ykx28NhRV!H%KS@DKj#4 z0LI+%I3v)XO3I>~p2qZ{DIxLCZp^U&U3{kV5;;n?ImidG_oz%!PNjPbCpsEUz;HO!#^kk-GX_h#L>dhL$ybm$iVZQf7Vaf6US9>=ezTC*`h9GQuONg&+K$-&7d=~bR$jV-(~=H3bX z%V^~}5-=Utk)FJB#UxKEThAM#7xLJ`&-X-(az=5MP&;vq`(m?g-IdE0D_q*gZxm(t z4y>-H<|8=U-><)=Ak2#`sQX>I$nGL_k(HfDAH*<6&>CB7Gd-*COq*qmrYN7gRSoxv z`j9^w&<_l``y9z}98ZOo1}v=2)C}P8at~pO=9J{7XQ^Tai|qEUk%H?ItE}t`FZZx; zexQ2(b&T_^t?Z38!z`CGAG1X+GFSQfoO_znfsR{-4x<19pe{+|kHGOyxGH9igp#VZ z7{@XxX&7}Uusuivpf!x7+ctu1q8=-mZQf;_7T!|IZKNRQ82N@kZlvJxoF1SWyMDI! zR?x>M+9X*>k#64Qa_Tx4Kmm=zXE{B_II4zV@=A!|Bc3+dD%+M(gU;sYr>D8+9VzZr z*K8|cYrTPz=4)a|ewjOYVSqR}>0428Yhg|<+Y!el#k@o9KW6d?byc(sHuIchlaqtj zifY_EX>cK);@DirwIxRZ!tT$@kV3Zyp0w5o65XfIl^c?ZINZnA+O$NM5y$6SEu>O$ zl21A`jhSwx3bIH?893u7sl^kb&k`Jj#6x563cz>C zKBJ6Qb;`Ujw9zyz3^8HEph+Oy**kbR8OiN{F`AADyw9{P%uD46aplNyhCHiqLEzwz za41o`Ij0vEYePJ?-fXt+_OdqMvfH^_$BZyN`5Yfy)8j7js>p*fl46r~P6<7IK8LkI z3*1b;XqFA^6f9+z9$4U#2S(tZem!c_#*EurbOI@ai!>{ilddz{2RJ^1o}#q&Xwn)# zG6xcsnh32H?a$4ys}=z9pOlXL^O2gb0$fWI?YNcZP(s4&p<`b~;B`4XlgTwL_mI#_ zJf>o(2bN-H&zX_^-ni>hTiseom?LP6r5DU)Bslu}ob~pplv-x8Q)rsbAGASr9I=TC zgSBLG7k5#ey#8J4A#3H&Y_}_JlX)bDw~$C9jfvo%qdR&W9tX8eI^4kJgn(ym_#$!T z$eOn1-T6uTk-Zo)^PWDrummn?%P6m0WAekne z;7?5$~?JlB$sPQlE}COt^)V;IUa}q0IwW(S(OE{O9>%X zL|z$}9RSC04NO{c*w!}Czk3lQ%Cs8*Wnd+fEWl%N&OZ=8S_P+=(Mqq7fxOpzkh$lB z^~Xx7EUqxbaU+Fo#Dlc;`Wkey+<7l)_UlVAHt(?;kXT6|{ty&ow%nd^z&!M>gG!g> zEJR>SsWy$TF_KASUR!eyyxqtTG4<{H9?H1?}7+EwO7hg zk2IH06p}XNA%@}4t)A<2$#W~oZxit}suoEU{{Ruk89jKc>}6U_CMkAUr*~Lq zZLH}WN&^BvA(K*D#T0YLBc#i6ZPkj&5G1!zfN}^R_3uhjDCL4!jB=S+1o??LJ#*XE zuJ1;R#x*BC6>}y&=!^w3EFy&{1L(SG~1<9Ycj^g{HWF5G;PO|!97kn z>+MvU;x|RRWoXpKFk37RI3(we)VWc$I&!)v5|>Q0j{8>;$cwc@f1W9ldD2@+adKo; za(>Sv1=|>22*~3HuRQX5aZ5W!4X}^QMKUj$^8C9`{{XM8T9za;3wR8M2UgzkrqHqs z;a5B`$2mCqcdVuR#^YnUoMfKEWczxcmV2nCaJi9LNw{X}ShjJ`w>5N0Ey0R;5eqzL zXb1qn_5T3t`+C&|EDQ`}Qs;M?0|hKT=*~W$%C;Fi`*`At6dp`rm_xaXFHlcV4I zJ^8HpDcgNas>wD%ZmTdeO6UNInbfF_Kmg$2W79v*tH73*oLkKd>np1?%O>RvhuhGP z(xkjmZ?wg@$v)I*)Z`yw@7MCDeTq21k}zQcCK*P-R@81gAGtuE5a z$s^zvZP4IvB#Z<6LmPVg`c;^sVToo79E})PiWva|+;r#P-`=5-pX|udD;J6Y3o*+Q zd$+jaltClhAcdRCm_{X8GxG7t$o1{~_^nkaqCJx?yQ9h?cWaCx+}!z_vDJ=1=iA<^ zE2OQDHDQ%Qd4@~{!sjDB`22Iznx}Cp$LBZi76{e1OAZS(ih1kDwm7IKNMw!XjyV+; z-a|9{@K7m2?#wsBTB9k1k%@LFl9E1=U z9G}bdz^al*HLbm{hGcowS(|svc8q_XKc!6^-etPY6j8?~mU8L{F2wa=$;cdb;16?I zx;7?F$IzPWJ;Y4#{O4lsja(?kMt`kI=A$fWD?=JCKGG#85slq?9st45=}u(}Z4yR} z5?w+2nPXrMM_+J#zLfwFF)rpuyBT1?4$z~q><`zk;aYz0mcpl1!IsztK*=OoSLK48 zzFvRNHBiYJkrVeZwBeT7NZQ1lvjLxBoDO|@Rq2()7ShMC=XT*E0g=xGH3j7NaYWGB zwVN!+Jni<1&ZDWr5tTnq+2@*m(OkN1b)#8S?JIT#aNI~j2w^WdAQmPaa_gnt}t%~QfM>1EDUO4tUOK<~YI2&>Y zIaBMA*0mSQn%8mwgKC*Fr!qEAJom*=xVd<(p57CQWy-}FCo;BwUOA~+d7!t3SrKK1 zI6vdwDFZNIdGE(L>q1sL;Z0bL(ILXhyyxa6NZO~BJoY>ck6Nv;3@I}(19Xb677#}Y zHjcO*&#hnC9mH)T1u>yfi6jhEoScE2;Bs;}86LG0x(1e6R#)@LX{1FNAMG*YgVR3r zxz{fG8Psu$8MNG7I8=CKi3gK#Hn4rbD(v$$%rHR=5f_o+P}1EPBvlzM z6r6#(lY%plIqR5K&xML9;)YdWxny9ftLg~IBX1)WF2EXB%!XEQZX|fgQcgZ>_v$$m zxuV5Nx@A{+{IoDkqUPP2IpX1i9Pq@B4}1`PYP(!S3YHSPmSW{eARe6uzdZi{O3{in zY0}*av;~=z#0FVG^})d>vGwWJs$x$pe5Gy{c@{|!;CW|-812SEIp@%Kx2bZdni#Wv zotViM5X3i>R%r-tyTI+wU#Y1~nT`VPSqUl;PC@4$ok8NC=jKupCXEwr>0ci<1`a)` zv4L|TxshH(g;|jbGT~e9k`4$Up8e@7vliyM4wpM(hvZ<=09}a~6=FGOWJ_3`%rUQ* z6h)5JT;~hv&pdkj(@H|D&*ur7$_?cyI8uFh2P3DaUbRv-I}5SgWH}(59DZGCHFR6o za_YRuBa>uJG&cd4a1tt&<&~Rzy}0je+pcQ3NUM_k#98edG7=^+oZcI91*!u9A})I zG2cfKEP#o_*>DAuSS5nWhk*E=PzJG7k9YdXG-Ea^7g!ov!7P3lEXtj4K%e zoD5_RPC4v59+k9V8yVEA6t*kD3`r};bUfwrcPN>>z#Fc4J&z+DFfmQNb&_zglrW<- zVdM(VdU6kJk)A%43l@11-I$f#y_+O4Cpjed9^cNNBBW<-LEcLsJe59!+v`e7#~i0N z(RN6Us+VPFf@NLHynNCD*Y!C1)n~a_&9>Ex&1F7Zg-bE&Kq`30_zJBwlC`s|I}%A& zBz@8BdwoSD%M%fHjpj(J~Fm|ap8T9`E_0{%8icq00Ai083fqA!V%0@v>bA!|q+Nz^~(*F84 zm7-G7gxk4$aly~mp0zSKnc#(@M*>0S%%tvR&Q3}0I&tY)lCIGUyre;KB)Kw5%LB@z zZb8XW^y){}rYMrmC14&lIiC`SRVS%9JagOLpt@C=HoC~x!0wIW!j){FOmUHlZMCq9 zX`;1>1-;2;F-919lAZy;9FQ}~^zT;-G-YauvFw0bhw{<{L9|4O6e{*LaaAv1ic+eO zTCUe-kOwCm5TN9NgUH}1R%(?a)e=aK20w{|t$r$@7RV}t7EPYSD zFeu+Nt$7kILVVGwQg($thu)dIx=V6nk|O9!%Z1EE;cJmFojxkh^Zed)XQ&v4G=SUWPzqvkD+2cZYnwjot*GR(HyBDhj_G;Xct zx87`=9R77eNLAz{kZtxalq4IOn;i$ZJk{PyMAt7QMdBNkMpUkIoae7k@+r?2`+Ie1 zq)`cJ4A$_5$OnK!b|d9E{3*wl=-MuAqMqAVj4Sz)#x26kmk0vx2e)D|-;dI+N&ccE z4YI)sF;@u3VFRZJIKV&W6&=8gz&_3zIb%@D<**sODm!^(nbXgG)6FjFCXzr#da)$u zH08*mbwx_oxn%@l2iiQuGP!6?xdRK6@{n?Q931n{(xr|hXIK_p(8Mt;Mm#D5oCW8e zInSvhwrT>!u4HFaK$5T#A zZPLbMEUP0QmNo?S>Hh%htFqfpvbvin)_B=nEarBNUN+}BIXnyyM_l{YRXeDYZ3nXw zFX5ILe9LB47cC<(k+a*VBdN&rs4hJFO)_n!RhDSkqmc*#Bh#N^4l(akWu1)0Ut-3t z8_9`|06j)er%r1^2YaP;a0@aj#H`0_WBS!!BfdgKqf zbDRV1>r%vlWHL=NwEqA$_m)4ILFhVkI3MIxiup^Id@Rp8vc3YdH>vgDQ>7O-6Z!Mb z6|WqYjY&I?_m90N2y%{`=GfU|k`)C?E4r|e@sJOi~$OB{53d~ z#M4Fse(EMu=BPWHJ-Oqc9CjY{l+kZ1<~*KZa?iV~XQ|C*>Db*}mziRKT+43e;lJmx z!tMtnrccoI`qgMm%L_HA3L%Z8xEn&TIOp8euOU%b;e@uzb}G1Hs!#IIH6&l?mv=Hq z?4uGiGC2VO1HL#Tzdz7bs3wdh2|MaQlf@`gY>~#$#k=hpBXNGKjAtO`ts~A@?(-N( zTM#OOpr1p@BAFuD$rk-Wbu-+t*l%*pB!}+p$MFtWXOEZLn%2I0-N<8Raccu^W^fco z-=9PNdsWJuS3^dlD3)%eZKYkj#>+0btuqn!}c;l$7`;VSjzkIMI(g8Ch!M4T;9ANydo_XgO;{;bfE#+g5aCa3JWCzTJ zuutFGpdrsz2a*UF1sTpE@IPLvv=|(~28)b$RW?)(O zD}EhDF;vQ1%Me!DvoaM&AcChqs3Wy+3-X;5Zp#AF2*S0+?2@CE!D1DpkPP#Ta(m<6 ztj2Apm1UJvPK>(;w70lvAq~_4yCi|@pIV6#u0uo_JhVAZb$%iJOWK=WOQ;(g~X;<-MrbH$vcpNNi3l8)Z(XERjsB2d&a;rAb_gS{WiyJ+myUGAxbe5=g*34;b9IIQrn!aU(+{ z$%cV$Hb&)wv$r@Ua(%!& zMnU7+qA)>oYdpf~3q%|DJ6Jm&?Vf}G0IgWYHkHiPl(z`(q_q(TXncb!FPQCyEJi>B z_=jGHwMvjXs{Z~*LlYR0^T9m+A4-XB)>MW<(U|9jRFsT{R_o9EL!rh86*O_k8_G^4 zlW)q|@BQEN+K*}PSeaFJdXQdS5fdvoifMOwD4At=z~r+W0Kl99-=C#0JShp9;6E{_ zh!xMx-yhDWp4lWOHjSkyt+bZ`NBC7MNbUKRqMm5uLFX$>cC&IYy>LPA^!irto|>F8 zs6WYQ(0!%aM3U61N-(l>{6`qUBhwY5Z9kTRRkz&~aFq%CC#TGK2P4v}!)B@^Cfmz) zjP7J5w~?G4Ndd8e$6zYdPZ5ow9&Xta5IKmdscaGsKs#~+FBREkU&&W?0OR15Z-fLmxMsROo2;8gN0sv-y9GRW(k%G*?X3X<2z zwTj~28)SbW8)DqMNXo?I5LlDf7$1dmwa(6pR=GTDB&jr^KHw4;Xw{TsjAN%Ku6=41 zv}uqRW{i-&bbM`I_)lZ~O#<&QqbjeK(;qQL2`i4C$3LY^hSusg+jNmNvD~_Fk)x2{ zU>pI0xF@OXc;Hg@Qn77K5UWBS7-jimi+7j2<9D&`kF7deAtEGzq;abJ<~~e%V=PZ^$E-<8GTg3q zjOVww0%*bg(2Oi(F$&F}@Xcml*p(hpZPGkrBoYdbZ?CO%iEi0k&aVQ+`=uQ-?f!e# z1{OaG@W-v-*pACQ%46>@{{7!2wYsMDnhA3fsb0Uj?tX^hrPELCaUou6pL*tXZ!F0)a+F!3ibW2R23VvA zoFC#`4l&f4pLL$5232tNd84C0B7P$LFw(pWcm0>4#%wf;d5l*2W4J2}SS%7X&&s>9 zc;IyIE10&{6GCq(t!*x2p50?tG7;sIz&IU9>(ArV*ROnh)D?VDJ?ztMvw{hu`)tIj zTdM#Lc^F;Qg>5#GUn8jEYzl*t=E8?Z>o!(?D|9DRQ);#x3R=_tD&tSRF$ zSyXx7Fq#V&}S!~O3Rx5{D(-*#gauLkt%@6B7%4s z&NJNg!Q!{AEN?H(u)Dd6A1Fz@T|&W=C+3%6Nh3W*YfDAFO(@59mQY>HCp&K3NM?mb2~ab)Ym<|l zpO?0I+SRp)Mz;m6-H+L(zm2x8aH@x#4&yu@ab9J5)a6fG-4jh!jO}e1&{|tbXCyX< zP=@l^09KkAi+tJ1=cgSqym}sUU3B`Ty_U%B!jlXO<(r5@uJ89x>MM%y{f(*AysM4y z*})>9hTX!Qfaicl0U%?6(;k)4T3W}iYO^(*a&EP{Ws+$R8*}yVUR3HyzjbPMQ>3oB zi`qq<<>mFY#k<~F&My_W+eg201G{T(I9=U11mOEu*g6KSsp+Q9_8Vq{as_!KJ4-GI zIX&_T9DiEyfnjl{C9jr|+uO+?^Khp!NyZ1i9<}r@hTBxXx3`y6jLD1%AQYikwclK%d1_meDtH#~3;ZlnWQS}uVF_M#U^moQk`tF&!C)gWZ#jNlWTamnC! zuA%Rsy_9{fG33P&7R;_N%nyJ3dymJpdNg9=OPWuAxcS^#N^6y9a97$j(QQcRw>L9G zY}t!83|`N$prK# z72#ss9M>;@kg2IoFPpLO?!P{ezAw{SJsR#!3|xUGk)%qnGD55X+RO-1o&m#l$gS@X z#T}1`bm6N*d!j~JBaYWlz?oxjnHi5pR#whes5$Rk_UV(wA8eCNNiATJqYWaJjD>HQ za6$Y9dI&lusp3I#Vd4ADD@2mr7Us_K?A${m{{YWegA&LAmxH++77F6aYw&50^cG$?4X;DKwiXb*m6J%V`2D z8%t~`W>b-l-8-K3(|jiIMu~H-E~$U^>1EikwwZ3L8nwCIysVidF#$*2Ba(Yy`|zHGd?qIAq=e|1Uy?%j#R#&m($1RNB=aWU@%@p{O!dv)myy?%F?3U(p z8sjK7vkngfApUjJ>+&1XK-YYvkxtzBOrFpdXClRpAJ3{_>#+1 ziqcyvs9>~|Mk2aK^4X8fSR7%vJ-(emuh5?j{4~>Hj@nrfEia&nM%7ViHay-P5vQ_QCRJOBOFYr1Ry{N8lkeKJJTdV6FP(HED$+`_Y>b%M zk58K)cmc)_9V^?1h2XbyHx8&c0zL|kK9$hhS;JurL`J1hA1TNIlpJ;Ar?ok#)Muyd zqH!Pah($U{6slz14(yors3)d7P}92c6H;oQw{?m37cWRist7^QS~+irzIX_yTw*&>pq6vBYC>8!2W}f&nC&%#gds z5L1kSy_6C`=yU!CrqLnRbs3t=_IsBXDdn+MCP&C<*SPe-&wonL{?3Zxb0I{GkTB2< zySe0$I640S^^;O1q$@OGqLyDQfRE;oqdub_H`2OzZK91^soFRLveHSmOqGs&Xg00q zAdfNx;~)*ndB@lErhj1Dt1?OEyez!=av0bTVmTjL>lO(9R!k@;0R!c2wO{}jmHWr$ z0=9)NW=g9gii*PC#z^)Xhlyut7j@y2Y=rZ>KYVh-9k|76+gcX^_HIJhh88(k$D;cV zwW!fVUpp2=48SUmjh|0yw2BZgI3GU%ewDmE-2~@jE9|PQspX+^dyYbr&-wMmB$iQ` zN)*g5A3{1~9OvJ!t!%b1Nb7_14%J>j<7z5M+s+H9TrUTf$sihh9BQ(RQQ|fO z=PKJlSqmrt^Mgw?3d0K~TOV{EuP4*|`&HzNZ}5zf&IL>5u3zN)z-~UZ5vMjcQsy#6 zBF2hj4r4fZ8vv8_Br5=2#Fv~aAYOB|Ej{{Sv4Sz`w|CBC$z zZ6vlfh2@V*QiEtwb45sP7dx`R@seBd>yLBINBx@u$YpW5LR$+T$~K(w`Eir(Ye;O) z0m#Q={(b5EAHe!m!VzU$$(GV3P@)!O3O6dg(fD`cu7CRU$m5X0sxh$(9!V^5TOM`hf>MJ({ znCa4KoM+gSKv&2{L~s^Oqi`hUfNT;6u;Q%8EwPyfBvTu%@Rs=-v%;u6GM|?x*FKz= zbKJ&;7=VIlVFzlHv>f2_FmsN_8LD1ufs+iGZOSCT+89FjpT_&*xGU6GteHZz?EdZ!vSUvW|LmKZQXw@Xmr* zw61V;l6IT z8Sm1$pE0e{-01W;3$?p8VK&c%C3fc{KVQnbXNjYNL{^NBe$$I?}G7?Qe0J0y;viGXs#LI1GKeWcya|ZpR&2MabO` z39^lYv}CB{H_8}wA4C0X26#Vk;S9p;IkIuUDHcuYxKtpZ^KX~@X<60lu za7vrR&a!M}62wW)a65La*=~Hfp}~tcEO*H%U;^g{pgp@(vfM;OIge}>>|=pK<$!Ew zp134r4%zprrrJjGakj;Y<(102EDpt0T_j;16bxsMrvo_ddh%;J{{H~%@&(z$VD20Z zr}g!zY}+BXq%2z9_YTmmo%JcG_F8HATJM;yxX7#nV6U85P#1JmhNl5B;k z(pjLmg?y$nY>Z{(AQEx-Rk3o%F|;gsVu00AbhiVwv z%d}^PVh-;?Ty3Z@s=AzcAk)H?4XtRv+q+^U6gP(lUf^TwX zPVZyAie|cRDrSxl6nV;xx-v$81B~_eH9V~paigk;jB=bHJQeMMT;+@sV9aC-CI&;s zPUZ9*_4?Jzxs{|+%evt4dNCz|d;JfTS3H*NGDo%yHO2)@z1 z#-7UCn$O5Y$Er=&Qx%Q;n z=0&EN*IC69Gcy2P^Mb%*8R#nN%^OH#2j?AY&Lh`EcXQ1vN9HoBKy%8++z#U>pTJh8 zovNkH)8xpb%LLBY3f%Aj$>ep(#&Ro2)Jc^nb2GR-IqBThTZL>ET&P~859Lgb@e8zM zj4NO{Ve=1Kl+P53;1S1MoC>;}lSUSCW^)v0+6iWK`EuCE7~RkG^{nfHuBjTac4Buk zat=Em$F*CUNZ`&eq-S6Q0E*5xHv|$DUCG_%lo=T7$4+{j{{UL%akCY!XWd&R&AWMk zOB2i%RBi}8PaVcTQ}0xwRDxT$g~T(i{jl5plq#$^;|C;y2p+lT=}wmRW=RS&s!BGi zV;?c^+l*$j;4ZjV3Fg}1q?s8b2e9q_6}=|QRLR;{ipqq!E4U+cD#wGLW0S|f;ZC$j zWnUrIMd|a~+%h|4^#mNL_Z5_61&bhM%D2wPji;#fts6^al0bqyPVvU5vHYN~Yyrl9 zoo&$TRA7;}E#q1lLO#hDZWDqDlb%O%53YL}i|tZeI(dHzntWPb+Bk>u?^v!b4_b{AP8zR*$V!BBqbLRPI z-cS;4Rcv7H82Pv)VE3;l);t%eUR>{j-8`s*{h6RZjWYVOsK9R6A6oTeaChCn6fk|e zlmYV}@gBclT2VA|K+xx45i+XDlH2(im#9nlqyiQr=gC6s*GZZnR&irLM|CeEa$$z``kl*1VwS}x+I zJn&DiY?{qSfn`we6_`#$k%JvC0s%b1q9TInO=vpy%436!JlMuL&81G1;)~A-B#^e^t8aGB+W|5SvGZ)$xO!XtDKZkEhw+l-J%*fd|qM@2rk&<*+(VVjRaj8%gcl?Lv*R5^Ji4?DN zZMLGv`@(_(d9r>xvy|{mo(l^6>pvqJzTz4k}pGv53%NxTSp(2o}Y=R@| zbM(&`9-^L2%rnRYW^}o@g{}PPLm4}-9W$J9%|%O!RMdzT-e9k4@`zR^Ei{t3+N;iU z)Zh+ytB-de5*f0u672=krmWnEi1Y*?Qt3i zi7HPSJvwCc_v=_V-JJ7_OqE0pY_qx~HwzBk(WnAKTOrtU$X}P`z`z8IikfLW#ZA6U zjUuYX(6DB}>KG1(KjYr2PJ~J2TPn{Vld>{N+&TXM_0+17#J*d*MjHO22x#`gL&w6XlZPH|lBuTQrD}qQ|@(0$S zE-mD_eUrwwAzKD!U>hB>dK#6jzS8&?p-+~ML{NV6Ht2H92w-pk7~==lvUahwlCdea zwYQa>kng#3=90t?2Sx4p)KHHlVZ=!!&_vEHk-{hkJY@O+I{sB&Yn;gIJc3v`n(fzbvF7^4UlobIw;d^x)&ADP6rw zaL|Ixd8u!@0FKkJ+^dqptQ%O~W@zF_tlVvptRkzU-PX3qg}o!JC@+;lzql+$eIN=|FB zU1U^>ON5c(cw{?nBWx7}ZDG@)=OEQ$cBHZ}lI70blWqXCV>rs^0gp~9NL9>k8bu-Z zWri#=> zZRIp~5yfqc%y1Qe7|sWNoO9B$PeYP&ZIi6A#;(!0Aj&+@6Dzl|sP{sq@zF=i7UCO) z0QaIRaIz#(Zl2vjhnTP41EC;r4tV03D$L9yfm-F6n`>us?f&Tedwx{CL9AE&UeE{wBsHBE?W_FE>O1CNGt06fA^*wrj`tegbJ-Q2s@RJqfFWp@JRciJj zEU6%o~H%tazdzFbQSGhv4eM_)tfj%n{KP^aAuBP?Zt z9J3NS* zESGG|&u!%r8F(AFbDZb-)8y2p6&0ZzUutE!RLciaP>iyJ>S^qZ>m!DeR+DVEETyk66p2n%h!D;s-SQZqxYl&h6ozUU; zFiZ^b+rM1YNUh|D%gMGKu{5U{1m{1_rxC{H7h{Gz#!qH5Xi=g?#qaX))&&s|1ut}liSro>iBEXHs3l==}~J?@3)AwO3FDt{<-I`p{np3Gb@Q@k`;S@GASdq4n%{M46H}WP66%)cqfW?b{&^7 ze(Ejp&eO9!(M6I;H;`mw-1?FZa%(=_@D9Qi0ouimbCK`OFOxixszV%~XUlJpp<^V3 z@~T0|BOvq8912@@Dwy)omnUj5A$M{zap_Yh8x*3hGI)%PrGjl#W+*axepo+RhBkR@ z2Qk3c&QZ)%R=AZRr?V_S&sB!yLHNdaFmMtBS{ zhU5}C=dTr7H9LICAIuT`(b13esf>3KL}G$?B#Kg{o5>_7VV%D)1Typ_agcGrs+1cz zrzzc%jh<9DEQL(bfa(Y#SoP1-r6g$nT!u(m7}s}}#~(ML#(UJGZKb?$`H_j^owo@Q zWQ>E1V<7bP98+Qk$dN9T$#hw~kb??y$m^5RmF&s8DnQpVw2)lIBv9MHe2JYGY@3f8 za7%I2lY!3}t9Gk2%@fHSX%<4GxeBM(r#S%U^3PLQLRnyyH^~@Tv$8e;TX!VmC!PmE z(-mqqT$Uk@!-A|zl1a$`ZOc8wf)F~C@WGI7Zy=lm;GHOe-a=%rM72uci-gp`{XSkVfbDLhc+E z>`&r7D(t4w?rxxDWN?xBk*bAR6}tT0jxml7bM4Jbn>j8bg%q8IU(@Z|hA9OULDEe| zZgdDECm29Qvjwvu&Qg9458Yf6M(jiDljGlx_iwu}ZNk0hsd-whee8%^_@9R3x z7#pSTvsf1FefP z&Ue3)DN5jGf2!<+4RvzO{QfALYr%^K)7%=27p+#Bo?BU8r#@p3TrPdgm%XLSq@_VG zE?pR&8XT`bBj;gq3o|ki9Bg3&*9g6F7(cK-kC@FWo6fl>-4kTDstqB_CnfmOAvZ?U z)8Z)t2Nk(sHybATLZG4>8?;nPukZq4>ruL6sy_^UBJA=44g~Xu=bq|7f`Nd1imS!_ zu`|NFx$TgMP8TCy3muT3&o-Lp0+8NM$A45|$Z47aKF_Zdns9`6^3FLr{9Lp9F>#lk zccbLltOg_`b2^1^L?LsC2eYjv-V?EJ;zQD0_#oNSKEGft|58~*zl%eq`-YRMhP7vt zPTZ!4AqN71oz%ap{1xn_#Vq1=W{LQN`v%n77yFKS(^zu*D`!2D|SK=JhAynG%a75(q)C%rytE5GK^ z;*^20iMx-AOiT$fD}7mwaGEiim@Z*p2xdMb{D7LrY{v%f{m`UfCH3c+I7a(b#qDHM z3+-*QG2&8rftY#lXW0{azLmyy_H-d?FCm{O1GNq7jkK5izvdG^$*Zeeo>mp=@*1_n z$<3vT|52EE`MQbfgsLQ~V{oChujhYymD$@kcdXJbF3H-*mWMi>^b0|pHZlo1SlVFM z-0%b>5_HCOGN*W6BW-YAoggN1rH0weGXkc`9|r<(tSF~YWkv(*?gGWnw3o&|@>2_~ z8p#fTT`vRcF@y*QIHi20S$EDLD7HHms=J6+Jn&{J5Jb-kLvno?99|1kq}yY@eKzF; z3SwcFej5r_DPU9RL$Y@;>(XxOjdXVFs?ZcOYM<=yrW5*ujd|-S(*AtTqJ-8-2{^&hGY;7iMo`0*kBP+g1CkLZ!}%hYl;3GR7{ zk9k*?9SSgAqiI8F_XgUhLk;&3g;7bgPx6`!_#_@I{o?4ffi$m*`Rlf02Mndc1{iKK zA_w-oY)W%}j3=B#4!+I1RfYJ5BccNDNNFSoI-1ZEd8;3FR@LthSuy#rc~PL*{rV|x z6=to72R~udf6F11ilj^BAN~G8Y%+mG1`kTNO=VBgL)_Px;1}btdNo3EJ}vW~`Osr3 zzify^{O4=|IO$vbUvH)Efu352C%mF1!Vc*+JBXgnJ zYr4y?G?V#S&_)zQAc#D#g-@OK(w;r3t{cp zRwN6JQ-y*)JS!8U(#`oHDEc@eeS^X?)%SWt-7eJWYVmp?3*W1@|D6oJmtI>}cG`l3zIN5AhPrB$CMXZqwsE`661PN!V@b>aMFR8=o zCX?}Zd2W7qK>sxYP8tLuV(n|BBE_g6&i&UB2s3qAmO6j%-?f3Zo9ZT?gO+z}B`w9^ zz>-ZM?^5xB^53SLTV|dsHyVc;wk}xgKCiaE!$J8*w07elsU7>uuTtd0x)F18fS=qNiuH zW_3i#>9=?NWP8wlV29~slXTYtyK6#vzf||#6p#zWI6R>(N#E7dEArRwkxVH_8AB}lC zbyzoino(;UjnAry0{R#wj&~$f}bAYeZxig=y~K=T0A*+ zf#V9y|8YO`tmMvqBCUBMJ0@xW+IkBOflf}`Uwwto-#WOF#obTDnF2T9^3@iocgGVV zimtQyqDf-H9>?{^8k_qb1AqR#piKYEPt8yNS<-Ie)2n5meVn@T5vH&=YkoP}Q`1dM z$zDf1+Eyv9Tfx>%?#1zZ|eT8qc)iv6;=%3La| zCFY&T)AIky@7w_);Q?nf%VI09HM8wS>BO;8gRzy~u`+WK-?0WV2}ov){(^nRo0p@b zq@$ZH4&0AP1Q8^kX-&%z6`nxBSUF#08ddY9zU#`MtO`4PoAAMWMFBpr&K-mc!m~N< z{lIO7Sm~q+;%wVJ)?q9LHVmm1mQfT;OU2k)X5sfpMCo4CsPkMG+z#(nhCdTUxG6E9ELx*1wIx5 zl2CuBRV}G2UkJi)vjp1*B@q-K;Q{dZ$cMH14^XIm~);d>1a*E5q2L>~jN^!#eSi+_y{LOdZ1Bp@h? ziJbxKBHy9uvMonfocgvGKYwdrOvzsN{f*pgpYsrzY8OY&6gyFTEd!|o6oImMjdfHc z>N>(_SF=DUz6$~*Chf7m5U0+;>TNM~ag@zV67L`MHTp|5pfWATGMWyZR!2F$)=?xP`lM@t5QT1~$3VDNtwby^yzmVW*dKG8=z zsr)q*`ve#lta?*~1}y=}=3Wr>P#!yB{3|_10-p^Fx94ZA&lDkofbt!0G?(2mPqLSW zWBX}9p`)+^Q9t!BAd#fC2d&!5qov~GY3QNjpkLlY$2})t$DGarEf(OWnjRd-g69b< zgsULsZcOi#dx6*nt1MIW6RK3`NWe`V?==|{erd17+S;U5>Po&9Bw(^Gfb3jzll zhf?WKD-%BoYZx2^7)ozBj8tJoDrCf-;`vh;Lee)!7lFcDFE5k9iX-7cQ+mvWH<2ZA zinERk!O|yp&xI<%FhZMlp?i;%n18fQyQB@-w$f)bdaFq`EwbdZy@orB^eeTO_Bq5m z*9NiDgdbl&c*9G!%(A+KiiGc3^?A&{m(0E%libFXr6t{J0*OFy@rAXcI|e?%%{NZ? zrIik%@bSh&wb=LahI4Izq(}MJMo;2h+de2~iWM(!i4M*9(KcCLqSmQ^Gs4^DL1+}|M! z^tguAFnNMDY)S(RzBQEsHXkYXQRHj2_OXD;w$lD8z(&5gJ;o%xQuT>hxp0A8vGSO3 zfe9P*VN3Iy1k+KQFjWQpQ=-aFJN6RlAdGd$8)Tia!m+@p3svv?#(2B@?lE0XZ{~0> zh^p;GU=i^dhAN1c7BhU9X}B3f@-*l@$vSvkd;qVpsesVz5TQ%b;8W~Yg>I7K7@;=} zy@K2z20tUGsT8^B55hJ>$a8KBI)4tIYTMbZ$ZGlbZzz_#tm698`MS^QA=-kLS&t!F z-$suImY7WGRq)hQ?QlU3W37;g#$5Wg0PufU%qRka?kwSc{RTBVkiF4 zR%?J4Wu8wZqLrf?0t9}l;bu3Fh>qEu^=52nc*hn*HM;R2PnfpvTP4vLe>EVbc2(Mi zc{|f-@{?{IjVO!=H#f7@i*6kU+zi9!tXb^12UBxY1G2 z5wG(-9{B{?n0h-8Lr2FL*tiP8W9VL24ALU5CP(rRi%5Z zxyXwE1 zJD4O6FGy&BfSTsIFg1$tX4Dlqev$WOE0`MO_klLeJ@wvA*%u7;yWe1>%Uh9OiSFIY z6Zczx-d74U(HJQO19(C!W1fba0j`uC^((ebL-IE%r15uf44x`ANlAHd<4*n8czggKSFND1nB^JKwoi zB96=@@580GsKmuuMbz81xRfHI+mHgU=~+LF?)UlR06l<&O~kOqn|xCde?1!2Uqnh> z+wCs}bCv*S9+wUq5X6XC8luUOHln?@KyyS;+Nn|&svT_im?i=M}!QJc82}N#3V_Yu7cKf&w9T> z^Z^fYY^C|eZWkiHckEb69P*{GjWj>npJ1NexT#A%<^RbU>w1_r4{m-K>nhL7S;rMc zhTxrtOU(Nc=FS|tT41hHYUlJ{9v?D}Dwnez(NfL&Z>0U<}|ElnDE8@J6SPQP0i zRb3r8CDZ?v@KM{LRJ4pr#mGBZ6x)>D@U&oq98gJP_nUOI>jN%HPe*_lOS%3&^T}Hh z=s?Nh5ZSaS(r;CxUHv52yPl?pJUNSDn@j2{I!5}bb9Nt(6N!(_@Lp-qvfu32 z`7yAJlXD~Vo{EtgG|JmqmJ+Pl+>!e9jr%7hCEcMGjtm72`jMHJv7%ia*ob_6Q~vH! zy2=a=3lG|DCpsY-5>@Lq<~_u?R^|PYU`|lSgc`N~r7l-gi)P2MD2G(GhiZ2Qu9o5K zT1!tkQ15P%(wmT+wMnGm=fo5F-$AHYd;>j+7HjaB{rpt=;ho%IQOUpE8ov$ce}?^n z4V=osWraLH*G&G}D;@X1iMST3FCnkJ|2dSI_DMRgOmJuri@EW%muFQb8^{NBi(Ekv zzW@aaq|@{3zcIH^e@kHUpVnOZ4k4bLHpzXPVpa+Wpw`r@=+#&IsWyvGOJsB?vFfrJ zg^!z5d8hY;Y2TK1ZU60&(qlWee_W-X(ds8KRbKpNi~w-Xu+Y1E8EZJRITKkxP)U>P>}r22>3VF*rjDWD{9U%7Q0IWm#FC?Q9$)m*#uU4Qp}6DY$x?#UT-FkmJ2Jkux&1iV^%+II0!cv+?{Br_d9RQyjuQ)3sgG;%}$dE z&or}i%M3H0)NF2fE})KeHln=i>%T2YtkD;ZV@>-!FzW6O*9S2h#0uJatH7hR+M8+h zYaw1viOb%SM&sQnN>R%~yLPjVo__b_$G~1xX|c-rzJ9b@wz+1Q0zjU|$#_k#dyh3k zeXtn=V=2#jyZ75v~+5e-lMo~H9=zG;h)!;*V&+HZZ zVZnKUmll?1`?!eE`XGqtqSgcP+IB%JY8vjCT=o4On=!Lg*e}~{Uw8l0nTPzjZ`)hO z*X#@JK*WGG0FeBhxo;)GhCoWo+LifX^jaIapa4WXD%J?N=gs-`goe{i{>0%)z1#@# zgPhQ|Q0Lj%)I)d=p0dp2Mm+L3vTV~;GOE9>uE^{jTh6ea4H)C$)1ErF@0Z@XG7?!e zN)&oVFbpFd)k2rcW`}B%vg~Tb-?7wuqy>ROch?#wZhW%UAg~$R{i0lAWlcu;sY0m< z`lrh4WaRRU5hy?yEqjv9lnFu(QsXGGM%xjVjc}E5GtJ>r7Nm@W&B6%d&!wCe;zB|0S8~ml-inwq0pgAJzfnqG+EXOm(RK-O^vWNXiM%bY z?}SvM(&XYUQ<`~c++(8|b^ITaVZChU_IO_OjU$ zLawu@q{NW49`IN%Ae}NzU~xa50r6c2c`jn zUiuhuQ)wHM=An?$!%K1;_SlK0hF>@>y-XNsIHtl2Yyj7|V z*u#c`FJ#N29rJCwzke5Z%kD+Nj%P<&agOlqdtEP|lnM)V5mi2pUeu%opN}Zz#Z}@a z+kY#^h-FZ!e0Vu6s@t%^{OTrUO~>1f}!pcT7p>M%vpgZk@qymEGg*60Kq zMub}oDfrhPe_D31aWC+zvFfYdF}BM!dbn}&Vq8YAQ7rp-VEXe-L$%Gb-LneFmcW($ zujW-{gC3Y@UDtX$Y=vTXEnYw{u?zbvppBIs#k$mlRcCwT>qL!L9a6ddqE@;@4`R}j zp(*gHWh~Ho4DvRlYJfyR2A5U&FQ^Qp!yl_1{P%64FN6z7t>DlV5uXcX>=SXlNPk{74D6wB)S1 z_?SMhZ%E|`U1o`3iwm(!*~rr`uRl3%%5W=0UUmxcm>Iw6@_@T@97?_3N_j((19-H! zZ-4QuR#0r*C6&{Qz1)V<%jMbpjSN;ikO0_C-?iF!D#@g{y{7Bzk@;*qE~YYIq~@ki zHN^7oyaE4#WjX}DLPGujjY``G$^S|;vGb<9M@V4J45`C0s++i$t85}^0Bw1y6F9T1 z-=aC|^=qHK3H)qbku_GnJ*f3Ali9*NR5w}B2pS{!plAYB%RWjh{M$0eJMXfwrnq@0 z$4kDE+`yYVu6-W?Ombg4zWjV+=~4oVzz3m1u6L>-QzF&6(;dtoM+*X=oIa+SCP+8; zaAHxkVs%1`Yzl8GkY>_i?w}(FN$k~O3&`qNnDxK_BwfG>k>~%A7jn$nI3vgj-SU2f zp5dhYdyU|(NB`Qs)@W5cKVEc5_$=A~wfK7W-Xz*C&dMLDH~^zoc{u+J)J@HrtlJlc z=Mkx?~d4nG8zXX2B?L8shzg5 zj|k}UYlW2{u#=&b%jxgmSAH~*pOM?FP*oI#M;90T$4YW|6Yj%!%$V^{v;CFN?mE7byZn$D|c;hSxlF8eY=y-olcW`aXsGST*=0hcVJP$=k3!uxJ2nj(P%qQTNd z-tTGJ8zlC77w`PMQ2_VlY6A5nq55vLW8%WyK#Zr=V`_$_sT?q8-t4#2><&M&wZAxD zOJ_jC{U;*++=^Q-+cCA_hMlGe+>6n}q9=vp z|CMzx2|I6Zy@qF4@nXIe_^s^pU}UDA&(%@;Xj3!aTOH#fYtRhcPc;2P?{s4QmM0C} z_>wh(Y3I_P#L=(YIOAk%!LbvP16^-a2DleSR79MmGlOUC_2=yE;SejcrIZ{I7&si~ zuJ-~sEtap3%9?xxkHl1rGaMMAJ&QB;)dXZXZsLo&e&HLuI-*(%Y1Lp z^2BY^?q(T08A-(FzHJ26{Tkd1nUjG-#mLevn{O)cKNlA@@6pE(T+ZIa6*L2~wY5JyuzdVFLSe95Vf36Iz z758QEjy)q7iW!afh0P2#%4)K_6tc`f74^^>;yjnXw#FIoi+Zsr=@L0!*(#Qzy5)xU z=z0G~L5~kQTxzMXtM&-)c2f({x>UH-#ShA&P5YpsssHH7x6{6m%ue6eN$A5 z&@GVN^v}RuOfbX@n>Jy#qAq4H1_>OF-^NB;7)Ov)q%F%^!e;N3b3t6j+Kq3WU&a#r z@w;a)f&LBqB~~fK%)f4xzTP!3cc?Ul8xAq;J=xwgNQUD3kqHHp{=C^wA;h?GUEb#n zFAPL{-S+bRWgy1HiNs?Y1a`nkIZowa`oE9n!gXl~2&S%PuUrT6KERiU45oj$Jk5c= zt!*)gjJR8kf7C}hDGPcXHe;xcsx77vh6$xQj^pLrCxYYQL1J*u=^1*)FPYvQ69WX^ z3~i+lLcO%#5c8`2$Lrzyev{kkiM-sMBM&``Y;&9gw*0NPSj1ntXDT&+j6;_e!b$1V zC5z(n7skt(-m~`NsiQQgAtG#r$vM3;$W|)See4fFBmwc*LLMad5-)72BE}0Rg74wtn>5f%pL>_~JuheFEyv;h2Al!!97yZ~dLZSTfzt7&8x*a`AmpdTeUCD)nbwBZU+}GR`>wm81DJyj? zY&i-P%e@5ctf0RB;l!Gg&wtROJL%HX*h^#j3TMt%Pp@pGJ8dy9J3$3sRWoa=k%zwf z`EPxWRw2|P@8vfzkjRtm1sIcoRgFJ#T~|p%AJf1gNf&vKfIKXLmL^IbNlxqUshu0}w* zlXh!)nklA|-HXpcLhwAY%3?EE{f`xBy8x6u`F-`am%rZ@Mgy#E=@<$pyCi??TAt2u z_1`4#3^j1AW$RcNHFx2eYzq6*t2J3s>~%4G;8Equecz@_W~l^m=~sa6@gL@>YrIMr zP?aQyHDN(%kCN9^H2fl!$LYBwqYlxBIO1-4q`8PPb_~d@!#cw5k}7^=7- zTiJt=@<%S}e2?5}ZXIIUi&lvg49`jLzt-sT@z41Am4%w_^4GGA&Gn#U^s4?^9rqyv5XbD$kG?Q} zFz;{J8SQ%$3vQv<-mg%-TeTo5fj26(T9T5fmru;~UrjDhgH=AH+m?GVi#A+{<>?LH zIep)TaXlVQxN)oRg}x@`%E9Q^W}$%%I>KweXs@ZJ3lrJ@{ecjwXs~1Um4`xfRFj%i z;%jzM{p4x_5YP`$W;PKwcA!5ffj~yPe^}lMhCXzC@7RVev0(MJNcGXPR7c9z(OCj7 z%X}}EUrtAfI(?((WoWvW4SZ?cp5^@c#bxK=u$axI=iSy0mT9X)P_{}Vt!>IU(D6lQ zeu=Ke7($s!8hF+(BzB+@bAOgJ3 zXgeZgfD{+h6dnHk=r-pEX^nSS@4N>-6+d$=?0u_PZAy2r{r!GVE=%tWcmFVAfxG8x z+9FVE<)dtJAcuM}RHMWUoWcg88saLATkPke95E7XPIxo2T$?sS4|w#lZtHY-!> zlzgK2Ege$(?4C9Ebxd;SA9I-}E|>&Y>wv)$OrT75R#*mEW#?h+< z9tEyIRmXEj2v1)gi-2GC{fusFR|dqqD;P~)Ut{5rmXY?RQe|oAMAPx(5amD}NA+q$ z@v2&>$g!Y%xXrqz4QPM0GrCfd_pdkSi88r1y6eTSm*<+K_~mw@N+WCpk$E__ook$A z5hp_813aPU3R8}Ggsdpz*bT-4SafiYImvaKR;G7{IP6VBF$=2A^UpzESgp6>#113X zi=a0=LHN_U)ds<3u^;u7>f%3&3p}K)%aoGr4x>*FgI=~7>O76y`}*z_M?KW3ED z;d<7N-oFV+79OAILf1D)~hRIxwlKNYWKQq+gRu$SRVP+zg;v#)BRlCg=<-p;NP8> zzb+wpZ8}mYjOiF^)c271ABRg7QY#+^kcUg#0F$0hn?YHTd0_yLh*G*^S6yF={TPjz z7JF;Zik{39k1h*Q>bs0kB(EokTL&~p#QMM$GxUEhGK@RQ}CC@L5k66ScIHd7|w)FMrZ)?>FO z7%I7)sC8jsuFS2N+vc|s$u?At>+9$t()Ee{H%um-R>hD9k20zS#xsbDQm6e08=Op9 zQ?rCVUVgH0BO~;jOnLBDs>jkD=1#L3$uHD5%8wBg4?Dv{r}&2}72OI6*1g?Mc191Q zYy5~h1RV{!pn1Ph5^dW(f#Fipeg_N0q*V8+11SbgYa&&d#RV0{uv*mnySIF3Z7GD6 zNx_9CLk+ms@i14+$U$NJ%haY9;_U=C0th|j%^)-_J~Kk!&wL7m;K=gsnfki-lxVv# z>@T(Dt#;<-k>F@2Jny;C{I{GP11^?6=~9(R%dhEOWlu%amn(U!hRBa zUQ5qE4~4SY9Me75OCty(j;V3G&c3d|_kww8>fF4i-8^rRkI!0aK}vDpV8s&E#j4E^ zL>IuE(B;q^v~zZLeo;Q5w8zPt=w2wB-*i7Na#&F*-Ji*R;~jeXIV;{088~AQ%4y#@E-)hEe$w*Phj#65 z8~%yrF|t9${U^Rb`(gA)X~PKDpn!)geH6z5xpC4KJ?nSiQL(4v73M~k)U0RAi23R>;ErCR zW2panH5uL6Blz&Txu>PvNV4;fx+>7h=FrU`(}P=n6mIh}NH+wUW7QexchJbw>a{7W zQJ)uB!IWFFS6Q`8YSI}oBORrdho;K`73E>2dU;D;k7he=(@8JqK~XYsHhqanYSg_( z<@P6~$A$E4$pvdh0x0oNC=o^eQNF0!mt0%`OPK|LWs2?B&&SB{VvF^-tpm;dY9r-u z%^fmjCG({C8;C)}RUI+%e_Lp&}ovbSCsDJF1t^u@`du z`bS&jMMrRVUhoXnxK#fZd<4n}h1G<%$Nj8W5uX{K)o1e;?fD;t%ykXmU)a|T8F}ZB zutMb#TlK%|I+JBV@!x6Nye3%t?f|rh+c{#Mk?$P^VhJc@$ocPkX|7zW%~YG~j9sMJ z+U26tqW}I&(#~=>;bbUnA}_G6%)mVzy4Z+3p|qh@i@ZC80YV61FYIR+e|@9FhFc1D zp+$Pq#+kfd9YL7%ChON~sU(ea@V3Ni54OHjqYwh9bnXw^JJV^oncHO6y-A`MDmS9C z)AJFp75rIl{F5`SmTdCN&?(+-k^m!#f;|X4{IDdU5%RZiyHX-50lv3D_IKQy$YlDn74{O znAkVJ@dz3CaXbdy+xOHvWj4T7$jv5u`${T7>mM2`6MS=92*mo08blQ+b2y>!s&@hb z`W;}Ceyw*5HwTWW)3B>hz;@=!wXSL%GFp0y{PLAAtq-infYU}o6^du7wmCXplKd%} zJ`8g;c)kIOf12k%Rd!WfWu7257u-K?ZPN24WVb_a=FCx+VnzaW!L&edk=d?cjzAEU zo;n~cgzn{-#6mc8(Ohah|ET5`zk8TYE*QC9ZT7ZL$gyiPf>GLRxhJrH98BI-YPy)@ z2=%U!UuDU1J>UsW&WW{DGJ0&OsY}Cy)5VNj{Dk$Bqu_|kS-fhVP2P2(UEt!?YC1{l zOVfvhk#8&`Kx)M_#YdNCc#wIhhDxtiOXPchVBnk7=Cf%4(-(-(aM=_|4KMFQj58K<<~8RO&H$o0)2RBCa6yraaT@IZ6<`1*RRk(!QB z1Cmr#EAG-7rxEu624TplehG;sW8@+Nnb@1NCrfKVXy>%`oVA;#dMZnYP_gH?*aFQ- zkV5U7N^|ud?H}Qvh7z$ZO*!c~_@|HO&H48ya&zRcs;hO+=uOpC6;xjB&b6_8r|FcR zqxbiGL#_m8_*rmG8yZ!zO}E{Xg^Q38d3;vWlrMv6$KPI_Zd7!TWrnuGY@brq9{KLJ zjqRe7e{bh23q|mXLUbQHXGM-9xuU|q2zA{1#%$Ck;mOL5_Db49ovx^DqLmO+2m=K& z3FSyulH)7gR)GlB?U?LRuM=4;x2|yncT_TUXH`yMi*|PiEAvxKY7P+8AygRja_6kV zzC089`c-MpPwM7v#WCNLe(nUK+>#kG1o8-7zLT-~vb9quz3Sc=bPuM3Hh=??AXD(fnTI#P(>fnLiR5@+TT7 zJ8+)BF-525XJbcabO-?sz}C-p=FV!-=N-o4iH^c=ttKq8Y9&>IzJ0XJS=aJ8)|?W~ zHXmK&C1m_M@#W~uVw60bHCw3W&}WIk{HJK8B=2crl_d|&x1(&s7NjeNBcBM}|q z($88L53=aA^n@=@k-uh0V}_dnX5V=|-&a?ab$NCr@~HNtZwV<`X!~fN(HzVK-5X0) zFKU&whQdW7n;Hx?*4L{?|9>=LBNXPS(m&+tPIQUYnXMJSpy3Q7CKg&cOo=B+HIcSq z0|XGU_hIU*LAlnZhJ{H#YUrKyMqod&9l5)|Yo`rgz*{%tF+eAdurZ!|m@ zvp=A@>j8u)wc=#eV%R^wO2y4+9+DiJT?4mqbz58mh&TN74LU{r#7`WtVYr4a(|Xu^pUpV6c12u-lV ze-KLNMIEJAC|0WTQ)G;H``?V*-_v9Fy(Y~Gr4KF@<2qy>4skfA*xMy$bacmrQbdU! z<7I>1B8 z&2=Seo$NdlH?f;3#*=GX(;`5@-WR`Hs# zq6s(oeUMn-a(NQf@I9{P6`b44!tgI6CPDIXSeF$F_plPDnaFwu@8n?I#V#f_$=y<^ z{(4~^-jyZ)MO5`Q&ksFe<_S{SaQ@iJ0kuq&s9w6NND%jvNw+0_UeWfzUrci<$YOOE z@=b)JbxF^!Gz8FkT)Zgqfb(@YuIOED(P9d-X|w*jw6S(e%5;@LB;Rq>36 zjRC@Gbzok0;&<2ud*r`8&FbwAeTJNsMdiPu<=kckh;5Bl2=56`1lV8um2(`intWbc zMqY^9!hS@}OxIN(XOQ_JyJo{sofmg8Td4}cb>=snR`vjdRiU^DDkERBijGvDIJ+R! zlkp*4`D#bRw@WKAFAI-_Xsa&eN1BNViKvVb<(bw~|L<=V^(C(Rq-29c8weteHT5I9 z6gWzY4RF$zkoq5hSz?#IR3!2q z;e&&j%Dr`GGaB25Fz>_^781%tAa?-`$aNg+uIcnc!lKF$dYmmixFxN@>Ve=kZ1=wy zQT>P76Kp1f0jzg2O47Q>VZzf3@*l^P?p>&tOGmGa&c$K_wf4OQa=1VIteU@24%N@f zm_|_R4nI0QuflGpp#=D<(gK^NXWTVsksgpo_QA|2!a|wpk9YKh?Q|{`^hj)kg9&-S zKEnV4^#ZnY$|i2y+T7`7?ngO3tx=`INZJ30SWu{uCVw|M6A&0nq5Bhl*#Fl@)e{UG zd5SbWYJT7KxW1k3Q?!#E?9Lfi(+(V9x%OtFwq%{+aZKhvInN8`6kyqe=ksOrcKV+x z$$cGdRwn$HlV3ZeW$W7)-N4)6Vt^3u8P_HI8%wt;xQgzRnw9dQ8c->;Ru@X4NI2aw zt*Z}4&uq*9@x~#%zjW6(5%V$9x{;Ob$B={xDAy+sUhG3=3q8>l@w-z>iSa%fV^?`2 z2O3fY`vVdva|xS8Y?`5$eJYiGCD*O1Jt7g^mVxTXYy*7CfMNi-sKtxz^Ol(=4=4u%Ed&2>T7zK zr)TYU zK&?>kiG&^7y0P0U)sq?7>&S>u$zT;E^`C-?qP>Z2i2T05q|F+ZswoNlpWT14pretn zYMv{@4Qp^B7VyLLn^Hy-CQzFeObbB}s4JB{$G@2YKb3vREsYzN7t!XMmut>iYC0Wo zAJL`msHW`@FH{EdyEE_(4viWD`yT1QNOMc?I8kEYxBr5hTPqvZk<`CowI#ow_{~mL zoBDE)VZXh3%dLWwGIDeU|050CLG3r?XwBSLFVY9{MhrCBOf z`PbJ;eLt@MirE;H2_9H8ZEJ>9d_!E7?5Dp`tvVcjnjd#B?LSPfmm6=3G72e9P9z(V zY|f8#^O;(!xA}V39}vISTc>)gig69nL~kK2@%pJI+0&_Ti1hydC`hmG{K$7m7B!49 zv9z`wwKd^i8InJU5y|w9pVkfo7oV#9qRJRzXAWfWgQRT7Fbk<52&Ol*lgGmXkM(~6 zI^F_y4`^wR>g}{7;QQakGsn>?BM{O2v31;fbhgcff!hU@?$(R^&`WWkIxR!#w+x-H zH8zUcS;?Ia*c^|7g({~g`rZG`>LpIv@2+Y3NlQLe9Eob#u@!p$uBtJO1hL^Elxnv4dNiyB>ezf7}T115PZY_ zv6PEYm`A8VGa%E67^{Y-1&mD_!G8G&alFpXR)u2u!B6ZPW1w=W3&RWP;~RY}g!|m|xOM#ni97$I%Kzr*n!_?y z`l@8F3rNs+y85SrtlI9hLFETG{3pJrHl-6pJ>m25tCy(;yQ8dRCN7M8xXtZa z6&|rk{=|OS#9f*#+m7*?hH=Iv`7*-(eCb^Hn=#=1XKbsK&{)WL&*FlcpfW|tS+v7U%h_)-6!QbC_w z36$rd$15Y+KNm_iW&H=z<}od=drWLrZ$RS+q+&4u@N_f1QqINZzUE0UL1JE7=lB&s zl1`B@smj3fuTANf-Ul~l|MeRUbx!7L9GvCZC=`=&bw5v1xS5O0`z1+_XXj<{6G{B+ z`9c3tz=_A@{|7EX(Y`kh?4`_-f-)7@k}=yIKggzBOpv|Hi)6Y-k8Dv*7-bB4Wlskl zojCNVlv@JfyIF)V$s#Izz)2b1!RwrR@l(SrhFGEkA#AX*ia?;1kYpA=mqYLMtcz7EHD|PvZ$lBZjPa_2SQ?8ZeVG>Ilqsm)kX|VKtFRglDh7^6bl17s_F-rSNtgZc8Z%*F-{9>i8Z=?J7Nvh~UJ>H1Zb5DOK# zw|A0J7tYQ$tZZ}Z*k`Z3Wi`rU>|mLQE%!+59!W77Extw|uswk_aV+J!o8()-_OKU~ z7jnj{oDAUL=OgcW)KSD?R+UL^R!nj&OZ5&(@`e=}b*;G+CM$8SUKLvq$C*o5;ZHi~@P*9qPH!4wOsJeQyj6 znIm;VaT~}Avg0{Ca6!)%s!lt9I>sij8v=pE^e@Wr&C_Hpib|t~jbvOx}`6aA=ww8RTV;XUfF) z>CQhotFva~5@}Ui_lF9w%7D6YxkqetAdaMu)~9SwGyR;&X9}E0bc7wP?bLPtbquTa zWiUv}%;Wcukjke#f1i4}YZ|0W=EkL3Qarf_Qh&*;T_tmxRU>`KB({Yo0p<=?MprF|HZi2!PG|E;o zLojCSJCVWb>sqgM8L76|!DVa%tdhws$j6qD!dfu67VD8@5L(EJH5kP zM=L~;2};K%#tM2dK8CkW=-vrQ+@hjW6pb7P2~4UD>aktQIV<0`2jf;}oWmkm+}gZT z$0TjGRApraa=ac2uwZla^`|wn%PPfVGpUp_80L^GWDNB<MQau0V^Q8k_{#~1bW(_onIt(?1E=^>-bH$`HO-*3W900(hHHTt zD&+jiKJyXRfsErlMrd3zv$2nmBwUW6Sbv2{EGSqRV-p*3kv`v;1A;=6&unq&S~%!r z;##NGEcNe zl^u`1J%6n@#Vf=vQO3}RYKP`Ao}Qw)`E2$aqZbkLMT?hI20xim{#~oM0n(cn+7#R* z?G)kNme`^NW{0q7X`$TLO1^J{9fV-G+k_Yht#%dDkWSZvM2R=oxWrNEAC>?t7 z{{Yvm#a6X~cH6sTi{=@2sn@o1E9}S+N~rjE4{?gwX}=1o$YTJ26bJeFc=I7$RO5w6C9{eN@Q8Q zwkm+Cfyo2gKAyFx!I7hB1BfS+_iUu$rS37`j^9ell1ZAuDHN_}n(2gJDn}q(0(UO# z_NtRZC!P>Sr+5M#n9C?6WP#A}{d?xD+zU4-Af7~YZ<05*R8m3v#kUjm0Dpx;YHobx zl1q6con$21+c+%4rU5*2*q>U}DO~7DEr-QAS{{YvkH>W#-+eosZ*$Hw^_-<}|wPo**QU*vJ`1PfEOv+@D{>^I! z)fVx_pI*%ZJH9hgt3SNvo`V-iuI^%oQ|q3D#qxq6M0fVBm-*_%o{l;>*-J^j705k z)5=jYoGU5EC#O#T0R4J&PVku|kyGsQf~hhbF()V2IsRN#ILF$iyq0+`#H`13@+$>p zBRx;v81J9d8a?Zpr=g>#P4t}nVI*4jC*m-Mno?>c$LMmLHma)b0$Vl0CApi+ao!~XoJjuv^3aA zNh)$ewhm5u=YTPhO}R(4WRY;l@<$vAvn5pY#~JI?`_#g6i#VkVvcyoopCpq>pP7c$ zY^d6BIqA&dhwIf@TVhw{yp-@&<0;J-A)ycbDvSpDt2^Oi^g{O za|HnZ0C=C&VGi6oCw6NX*sJzAq`0_- z&LDRc9#RkqYzzU@B-OQxP?9MUO_4H1{-{I&3;`c8?~{%`zOUxdz*5$4B z2^t@nzR0Lv6_cl?a=eU_+|*6L#nR@Hv8vA;Ch8caR$;l3_vNyBa64BpQ|$!DJdClj zG=q2D^9Lh8jdD_4Ua^(haxRd3`-bhMSb=f3Dd1XiS&IM)OEKcqf_b8F1byJe8f2Kzsm4|T6G!FA=c)%%(s{9#l0Z*D zLE!i2(D$rOV^6n&DW=;U$}DW_<{!Lv=YVi>4?KEzrrqn;4ub7rX{7R07}Fm%2SJ<+ z`<}h)Hsbz!h;EiR<0{tdku<7VW6JaCS;G>PmWQc@qcu_|_QETg_M z+^k1wX#wRjaxtG@>59eDw7cy}*5^~Wy0WmE#t8n$VF@xbE^vNj7!ADwKr{O@XriZMs;hbZKPn+C_P+s2N@i8 z75N7cW1se&M=2lCbaL3No*HzyCZ{Fttp%mog61eKln~LWXJ_bL&mSpcz~>q6X*ACd zN)kzK(I;6>3#{)ENm|esd*u~D&U42o1QWO;Qea@PKBnuk4pJp?adm^ z2~xS*206gTen-DN^Xk49@V29Idkj)SEG2alE1HUS4DgN{J=KoFm?Ez@nR|E{; zVU@6Z{sdP)Z*?Dm#?KDiPkniCqj+eFvnT;eKGC!@1B?Q5gVe?xx4Y%JtzoBKX%|zrnJ=DNHuK{TyUdV( zKK<)@_Dc)jvs%5pWQ#@nRC2^N#~~*;IplO8@!#rO{+r?Dn&$0H{$zi+AxL~23}6mH z_4casrL4Mo3rnB$i>U)%eWL-@iDCkPNgyce$6R_E@hew!lZ<}jf~=i+r!9QUZBt#f z(yi~}hSBe2Fl~)zxh6Q(jyG}1+mb-Y8OCxruPpHnt8~`0yf?GM6d!dh*r{dy>Bf4F zzomAXq$BLtk`nH06Kp$y-6UX>lgY&0()cGkq}Gi?3b z7f!i({#~(-q>k7fzLnrQH;ts2+-nm=;z=b8_VPaE0diFBJqRT8--`6F33!t(n!M1N z8d?0yd0hmBS&nv)da1`l>G)UfnI&jKjCHyBrY@A-NnbPa<8#A&fHH zT-mDv@#h(JY~YpoNFBbUSJ|Eu)1cNYMb*N$m-9EA#{fnFIW_s&;E9FB#8-=uZevnN z#^!92LB|*%6aN6}uhUP3cglP{V=Qs~mL!jE>0CY(a8Cn(dVqNViv1%4S=38If`$E- z=eBrr!N<2`kVSOIM7N0CP9q4h5?F);l|R$BxO19fhWmX)l!| zP{SG_D$(EuRvdyok381o@|aLGcE(RFPC{@G`$Xrrx2;8Mz~l(4KXA+Ywpl@7M(lC7oFA=7>mXKE zhkD8amvIKyU~?*vC`N zR=I&>h>XgTO8)@7k|Ty(o^~^^2;&DB{zjVOWn^Ru6KBu3{M9)i@J`&X zAKvHEk(CO#A+X~N26O4#n!}f{G63aSBl7pF9$XQHJ#v5g)o9>ga58w!Q%EF^S>N|t zWo7${Rk*;(Ip={^`2(Mu9)g?!DP z_mnP8TzPB*sQ!Mm#gQ90U~$))esfz!NSptSrz&QT^WS(+;MR|2Bn>Uo3L2*2CNF!qDi1Q;xqz3k=mhB|_JU&Ze z1Gd?We=+Brbo%10%p#DW{{UBl%v%}xy$xpS6B&>)jBr*!LBRJ0lsSxfuFP#oB!9F) z95dZpyfQRXBqgSdgM}MZkTOp>JYag)1AQckadOMKp(>29DuISy(Ek9RTJ0|)5%7RUsm~+X<9Xn>Y9Yf5wS3@`YL%CG|d4Tc2Be?e;(zKT?wL0ju(8Zajl0DD| zjW)jDF#hqdc|Sl%AN_jh?e!RKV7Eqa9k&)p+^HZO;AcI%{{WH3rOU(nnN!MkL%bZS zs`VX5`ORLC;i7+(i2hYvf-&{_*E@EWg-$BZL(pTr`$f1xBxJm7BJ)(>9(nqXxc2(h zKR8=XBDt5%o*2}|sGC7-j$CpWV?1%x9@Wgldn|(i6ti5P-Jw3*4Ey@l!l<`Zxw$T6 z4g26m;g3xJ09xKLb~t95W$3Ox*0PmvoXQj00@$#4LdHP&oA`@vVz_Bxy=D%u)GKg6%ZoHDQdN zyplZ!uNkMzq%{pqacyyKqXJ159B!DdRhWNfg+(!1&GhJKQ6q9UHUMm#}z0S~2zAK)#j%AUSIK0Vr6@&~c z5PM|${{T;F(TyQM?F@)^GKuyOL2Qu6BRuhs!`hYFGN|O4)!JOea*{{AzCuBej4O5d zy+{85s;u2ckii_{7^F-TB+M2--l2Mt$5C93z0759R9v`2E>dWAhAIY6T=m8=T^+sU zrOK5?5?okif=CYbMkCN1bk8Ro8cDmHu1~osnXMh1NS<4(DMNrdb@k7Bnp>8h-Z;#6 z2#`h;Nj%|;H$03Eha`d8v9FOXL6$iKuIAk!V6C2 z!ZJD|86Ezgb8$LFaWpQH#^FyOl}z&>0Wo937;LWOU}WQ(FhK^E)-U zXMu|bXNidpsgM_^KbRT!s^PAoS?7_Iz!8B^g-Y?sEyy6`0rWn#kn&9+iK3Y$05(=U zi~tW&(C0s$M)S)gX*|mN3}iml_S;zKA0K3Lwnc|3ph>p|c)+e(?@l+ePdY~LwiQ+i-45f|C!Fz)D^({mZ*2P-0(YJ5 z+jEr&L0li3Jc4u0UWm;Mhj<*u%wuKBf$Njd^sabai+S@M%gqv}%Lxn1ZaY|xaB=+q z02;A2qvuruI)f`{5J2(4CG6cVK)R}UB)w{kfhFxbaWUrHUeq<0V@%P8y;~+kr|bO;I=y-f2jWe z3X)k2@<%!isHb|u$W*ca0BCWX`WkdIPZS~`Aqvte+sM!c+B@(De=5dvl*_Rr3^Lm^ z__UfL#@Qrj$m8Wb0M9&kngvbCheLanb= zKt5FmuN>prsLLdmQqMVM1VY|cBif+u8*|Qh9ChZdHnEJHkr|R(i9{_Sm(0e~Bt!)O z_v!(wWVCNGNf?D5SvI5N1SvSjBw*kl#Cp>LAdIYLKQ?ch%#eV%1CS46?0vmy_DK<0 zW7Ha3dvOyaP2~rXToQQap*TLEAHthg2)p$bMxA03x0NGaN_?>jg#da1*F8VUr@Yq} zGKlvizy7yssSr$A0xv_2l!Sl|E;hL$webfIFOwVAQv( z=fJXoE6UTUxXYc&oa6)BKTqdTMRfBOw-AFQaV&7pf&zk181~OUjw-bx%bQ{GP30h% zBD1TqoF*AVbI0XU#VbXBoKVk%WnSwIX`)n^yAm9TXr95Mn#Py zlHHnVca~*r;{|;WJfChk%||SebCSDdk#7iuPV8OTi%~XnF~nP^Ti9d%^Xt( zEh7Wa05C{go^ilFxH{q}94;d%<*&#I`A<0Q#tt*jYOL&SdleMLC(3+-_TW z%uGlv-iQJ0FmvnIkIyM0Vp3O;eEDuR!oX#e1HdD< zzJIM;UZldMiDw>Eiy4mwA%|%40|IlCl1@P5j0&1a_RS=A(o3}gXyr#L%((tA4nG5$ zd9|F~#@9Jzb}BzEf{Ed1t|Te7W8T~`+mpBa{*+4B(CJc4%Xs8;W@Ke?{;{0kZS|`1 zw%KHkB1}>!UG2jV4styYxcXJ$3m89rcO>l)+N&b2>}Mas1w*mYSl~rNFqL+?$L162 zqqjc(l}WT3F=tnfZO{+2DDwC+81lLKk3-1GIPcRu=C7oGy=!#y773wQ94ig1+~bV( z0RFsps6TRxDh=!gaL2LFKD>XP)bk3%c(O+$IDtpm#BcKM!33Oe%g;ku-Pjts7E37L zNSYXJ76{ZT1VEv1bJP4ktt7JnZt5k5Nnr}f8w0jRBm%3(G6y{1ag6gqi&eQveAbap z(9kw|!xMfP_6) zqHbnL{J8eXp5=(^pVOaO*2v~Zf&a-iFvaWYN z8JF6SOEeJ%Oq@z`9dfuGG3ay6Ox|qXMCBqcaVU*^+l5#22rcrd<&>(NkT}54T26A0 zP_@|mTgh!?o9tIJLoA6R#d8#fHrs-v5)VQN1bdo%0@C5Uz&yho3InqO%Gu}eCqLGb z-Zj`Jnno`yUn(;OSo-7-$DhaEpf3{}X%uhy8|^C$i3utPZ1Izhz>-f+wH(StHOk5{ z`7tbzq+dG9#K;uw+uuKr`QoNo+s=o|xv`P}l6mmlEQ-S*kCdqxDo#dn4%|~M((UAI zK#Z~?iQSxn7d#vRkH@`FaSJiGk9D#lZdlPH#Eiv{EPIS#W7?&tkD9|?eas__2hQDx zB$hq%Pn^qevs_7aB(f~(L6Sqb4014fgZT8Qq?#CRHY{Fi+v6o=3(3c99FDwk^{FKu zaWfdgM<6mG47-**HR7fn&}=Ff>|VBPVlG{ z?kA>4Eyu5a&aK%bXL3q~ftPA-I9vix>HR8V#7lVAXuEvDus$1a2ha`+b5EVVr8z{c zHN0x6=K@}2RwSu8K8O4%uv%R~v`S5+X`izj=-8^p$0Go9w3D7aO-eHjs7H95J2pgs z?v07(2RY-gJPNBFv&iz8S)3MCW@jvlo<^GF+kqQMx!Aam z(d-JWN#Rrs^cWOOkCQTg5bgBn8%qWaT#cLN1uMj=xW3g9fYx5sa%F!_vW0_ zfnsf(Ts+yt49=cZZJ$6gd-w0{ROMqC^JI!iAX2Bwjg%H{;2v;$^Xph$vE4Y8EZ%pU z5xyddc|5Wc5-D!EBa)*W1Hk9h)KbJ9e#;OTs!%PqQ@ZOyCCEM&qU zc45f=J^%~}#s?T4^vM2x3NpUIy?5>byYt6<S2)VXdV$ua{o-0gL&~tpDQ~kM z^;rHEVbxd=K>E^6Ah}@#LCegnhFK;hfjx1@L+C16XmNt>M;k*hl4oqQCdjdXLwCpE z4Khg;0S-wKNwf{SSdL2IeLIfy80CsYjY@eao?5X3yGE%tTHAdxdtg6tqPdh z-!c`>aHQZVCj{q{RUTy%c*A0Z4D!OG_ll5@oUl0=C$4^=ejylDJfMDLhN_VSoe^ z+#Ga1{E+vj&RyKhfB!zd%2^+id*8{1=EL)Xl`%Eky zlzo-6v?$NsBe)~CxaYNOrS6eQUgb%|@8(4`?C%%)xbj#=GoG2?6X{5vXm2i1(niW# zp)47?H;YND#>N(MI{;ld!4i$YqV4qj>UVKuH9VmOj7XRtrd4-W4sf1@dBq$WAvl z?W#RD7Cdp2?^a>E2H1I#BvMT&1;zsb&U<=OSVAP+MZ~!v!aTo}uYA8ic^Dn?eJZaR z9)xye1sU$2FSTPrFbUzhfIAWIP(ywTk+GI(4%u9gLjHKqryjqJI(zA1jm$*PHuJh6 z)kjg+j2?UTG)gWE(L~V2a3_gb5g-j9l%9TmbDl80h&3AANqGY%!rp5u#K5z+A(VF> z+3Q*9E5`9jXyH@lT&tBTr>M^d1QS;S%Oq08F7Z3bmfpKtpUeFIu&fE?NMVQPic`Ow zf(KwaY)YX@HuDzLb=|quTPHXmXD6po(~nV3WN9X7WFf+k7Y8|CW5;@n z$cV)4Bq&%!alSC}Mp*EDMsPY)kx(>o?w#%$;x)EN;S8?0$;rqdgMbDOeY>a4D;PN> zS&7!o-W<#$W(>){D$UL?I)Vmy_o>CyT!OJrx$@d{o5HBa%H(m8$pe$hobY*uStAfj zH0seZKg!a$Adckr1D>9hQDd4|5td$9VIRySDC>dkoS(}9SZ(JTZ6=vl( zER2l7{$N*-z~i+^*BC+5xZ?^1j6?(_7)Wn=w7Jp9-I4}^ zB&p!@_09*8J>oDbKEjcjB$E?W`FJO^S; zBB6{99FPjJnWloZZfL921eXA)Uh%wnTQ5Nh+)mRx zepGhxpCTL;P!B)`bH}|wCEVq9N>k61K5UE&DwFlWKh~r{Gc@;6`Em&k)Jaa#7a)xF z3(u#gy)3qpMoiaVGEBI081obn*XAFGJ?m8{MQC%?)2QD)Bc3Rtf_WjBgDuQxzFHoB z_D+4c2dJy;ku*@j9ERTIr*R`(+yfknp@<9H)b%+805jJh+d~u$G_uDmGQaNA%PK592;1=YxsN%ZTahB=3kCB#6f1C=Yu<2X6@u6ZpvqsUNQ3?RfAou$Fdew+0GG4TI4;hL$fsJELr*|OakGu!J zeEQWm;uB7iF=Ukyg#8XjZ=uf|RM$=et>jQ4nR2ko*xaey0q9OM^c9^sYG{c>F~#<` zh$>{MkdS_3gU{4ed0tr~w|O3UE;g|j2Mn;r0OXP}jGh7hK-Hsj7-)WSS)yfRPzsVy zQ^7eMKN@p3ov*0Gcjw1oF|zkdFlWG zkEkEktt3jmUzPi*6cgp{0dd%R=kfe153<`5tr|n-MKXki$-@9a+<2>!hOm^hfDQZ_W%o*Jn`PTwh7oRb5$8$D+ zt!T);U`Do7^8pV8QcfdP0CdSe&ox4O)r^u(+5EDW&Rf?%UqMk? zOo=IyH=X>45zXhq7BIsEZR#0tdivxVZ<`$cWS|$!?YPU9V8rL#{{WwAu6d!;rr<=- zTd`w0+$$5g*tpuwfs71iApZb5)sHbn<=R1WbVPgEG9;c>?}LHK_vuvGpU#Qn!AN$w z3;|X?o`icIDUTG=%n*6REJ53A5WJjq9+?!?XKjv)ww9tIkG2$et~{xt5=V&1Rc!Jy zGlQOa_s2@TcL`OAB}a*#63~YPFj6{?sOKV>Ct+@)IpT`z<`P2eTWB3g?SuL8P%Kic z@|iHM&;=pfm2C0|2chVA>&0a`yAt$6=kv{}G36R18)QH?73+`0arn^W#U%R#TSQ)B z<~;5Pje+rzj=b@~_02XY8_q+_0P zed;@?C0U}CBsR9n8_Iaxt21Mu7{@A3f39kq3z2XPzI4kRWQ(6HqOx*ApKu5V)byox zT1gr)&XPwmjq4e<8)eu+nFm~v-=`Hr?OP<0#w%ilJ&JVHYty+Zb zak#d&5u}m6&Gv|sVzDwufIvO5QUtuV2-e@}LhA2xeWF07G(0dHRFi?o2dU~uT5{UE zMQwMoFwjbjBiu4G&M=}nGDuHx_4n;kEw04- zOe=GFEYY8k1y*J!?yu?B*V?xBYF$lIb`~XT)kbNXgklwABo*g8@$LHhR5PSZktDNh zg&gi!iOVlVCu#0IeQMpbGDQQzWCzMP`6MR_cp#pbCnM6JXv{Y)7ul`hlGk&x+q%gd zj5z8t8|%>4k>rO_xwy7ETY1*ip5M>5mNqQ|726{&F~?#UdiKY?S3z{P>ZJ_Q46Dea z_lkJO0AS~mf0bCbx0`!i9m(gSjm>b(tgE}7rLe3sj3^o7IpU&@QFR=a!LFl`WepKB znAEmUE&(|hC*?gj^rE8Xv67Rv!FtFdPqMqoJ{QQC##?p|a69{Etw`;DvP(SD$u+<% z#$s5EcPG^QoYh&DI|fGc6(UHQNl>|EjfdShKf~9PQd%39f_T;5$_LuhER4+?H#lR{ zrduEH8qP3nmt;`;L;%SG#Ic#-Ss=K3(~`s161e9KI3U!iJIir2{&ZlKSjNN)7>o>O zXaEm<4tw{j3S(P=Y|&fZAyTo#@_fZ}+Z>Uc^fd!pr`tZy4Z6WBk&VeCGN6nczdYc9 z(08q-uNH00)OHva4<;KcmWmcxm1CMr2-F71C#m^xF@f*epByZv;!B0g&NnN@K`$Z7 z^WQvot24(mn;ID*h95aqtzO(Tg-2K4*b~qWdghk;8>r**KJvcx5@6sr)OQ=R*0`na zvU!l(Yf&hUc$Hk*;yKu;Qdb$s9rN6dGgdAc?hNtD=^U?XCdP>bF_m7P+lqiNIb)n; zn$1^|7?3lF)cw^b<}J|V_Xn^&DOmuzTXZO4TXQ6lL&Hef;Gg!fk=vyZlX5bfWx$_m zwzr0VHa1vSE}14n@9F;l)~MkPk#HsXpv+7d=OZWi=B>udB&_f_l)wh)(Sc~eJ;l5*Z?MkC@|gFSi^XwQe1OAeqg_+BY&=yUJBUlY_Vp zzbWZjFKH6$J0gU(8!o4wHFhRU#ILvI9R@v)3Fp`FsFj_TCzdbtmMj$%77LD*p^KY~ zppeLr`EodLTU^hfX5`NjOU=_@zi@(g`}3niX#)&G3 z$^HgX4&Hvb{AzEvgp=%qsJFYe3w%UM&QzX={{VSgftDSzIuk_Jo7yB+{oqL(%?=|X zKBNZhdVP4RvPB_+5uY;P#=koNN#_|j?^QIS&PmCl)S-Ncg{{C4msD4bi3U{Qu6Z3s z52roq!^$0kq=Rr#x=7qI4Dfm$#++3c{`vlPfmT3(Du6SL4mtPgd)8F(LmUF!YIGV10?VOCmq1WHo&??b0W(#q|5S$K&={{ z2pAm?UVTqBBv)}jkUZ1Guk%KSBnIQ4>ywHiVka@jBBB*0%1L6}qCt`}xf_?%XQpdN z({e>kwu-uppJ#&IARcEi#HwFzD;X9I(2z#fZ*kx0Qe8{(G@Tuf!;G68s&v9>tWLJOnYDoE1W1%~bJ@f0vZgRP*jFTxta`%^zx-4lol(FF< z3cIjCI2h#qXD2+GoZ3kx&D;6b#wdWxiNIxGGk`q~4oLR(piP-2l6X>Ne6-CWEX;f4 z_sv5bHVh?(($+maqg;~&O&mK&^ge@wT0@pX*n(TNlHHa`Rw#=qqK6x#Vt4>|$0zWr z`JPmbQGDhS6-DQ8QH=A9cj@)1)yzeFv{@rY3K)RE4_s7kO}g8>EpsbPbT>wfSRKcJ z7o2i=Bk}25I7LTer%P;THLshxYn?(Dx@ik7vWDE*Cj-7tI-g@y<9O|w30dVr1el67 z8@7^1J%BmJKD70mG|cvQ3S@jLTg?axtT=2i>T}LLb54>C@lU!#EQu3&P_f}6(ppC<&n$;{ zkr`Syga%ayKPl%Kz&RK_MOSaOhg*A67B^P%=8_zRBx46|Gt}{#EX^Y|6~3g&Y$brP zk>H(W9%2ZI^AWmW@q#+%rZeqPi>U3q=rbF;CA$Hh{{UL4XXSvBl!|#{ebYxX5TOrJxaV^9 z9kMy%t=wEMojJX_WVM$q8%X>QPQATz>snb~Qz=cprHIug5ltILzc}2bODWsfeGM#% zW|6IOQd!Q}-3QED`+#@P6-^_!f?Ioa33Dy9q6CSq14gU6B&&>%QV8JH$=PMP3n}w1 zCAnp{*!zT&E^-u%hCCC;rAxJni@Gb1v=*KzVH3uy8q82&AO{=25(JecJKZpR0a#(VSWS1p>>;V~?YFjx*e<{Ok} z+Kp~#^kZ%Atsw!v*Y=pDRx0W90>qF<)DeU9HEAJ$Tgv+*6DSVMRI$2sYa4hDTlsnL<{E+v3&jy<_~L0qmrZk%#yrWP2Mo@8<< zm+ss!mStvEW^QA{Qjc&AX=^SZApO(p_wbDcE+wD@g+e zC0WQLkW)`wK6pTn?^KGP? z%Ov{XbHL9|pN&K^T<#AOso^okJ64tKbKFWUX5BU;W|DbZ<|nRCJd^eB??@M7GeruR zTn68QTXuSXN|?#TqpR6_C|qQ+#vl=GV=&v9SOzQ3NYDB2OcBR&vbsCQ%NXAXiA*fH zIXm)LGLSgNFnZ)uTlX=&_nNlQpk|V0!iM9W-rIWr0G!OXQckwBEY_kWlMgD{v}&=O zoz6L9fz*zDtF2Bisf|gtRY?R;T_8U&T%$7Zr__&XvmEJfZEPp=33AzO-!nFP1JAC1 z3V=ki%w>s^B#jxRnoc8P27k!w)4vsXTqV_o*;kz&$D^B+C!jnYhU(Sp-%bdvA;B$^Z&o!QwlKE`% zkR;1IaVZBa?bkHO#nr@;$u-raaTRFivbeKmkgo(Xw*h(MgPsoq|)gmky9AK+9PDjc&4!9$Zl(}riqLBGu1`s2<7ZR)P%L14lgOl6y zBZ_szG7yUn)Dl0If?#mXjxs+C;8c>tBA0oE%BfwfysC`U&XUc!#B9D;^Ctk6Z}v#` z$A58E8K}zR=8Eb;V`MHWk>`2E92|W!3-p)8KVBHupv~H_{ z8CU`RPvKZ{&MeNHn~|Yw9Cz}V;}(lNhje^{FF{(L|Q*6Zw(lXPDuYkD&T`^y%+Kw0=XqtOP_J4a+jbLdKcKJ-8rNvWGgk z=;+{Dm449$!lNy<)XIF1IwHv%dw@qC*%|ewDm3c_y{_v#ys0I;dmRbf!25BE66!0cnolx)Ez6eOYo*6> zTO255VYDj{13BmkJ!&b?*hh(Ce>2NmjOQwT?gt|T9OwF1OckM`G^qJknH(0jMr2po zU7sjO2a(PPyGI@&bDW<1dQ_)ASIl|Ro4CccL}Y^4?~>uaa?u~&9-k`u z=B&!5c+plzgdt_Qfrur&Gx=kWdd0kyOEdkTHJn7@ndI8cx#58ajE+V*{CKSyt>T

da~p2Yah&w*YV0z{8IdEJ;wd13w%diz+8ZYf{{Y=! zG6pa@_oA$C6J(Q)<@?FN^3!s@)>S+b06gFyW9jH=i!57GXNc~3+BJA11cQz^^v*JS zb@imWf+pX-O}mkI-3^_hC+_9&nnO5;i8PFjj%{0HVDDsoM)c(B)3SB zEx=4hIsh<@>x|7 zV*rzqMn3l(am8Jh6%tFk%Q0MGQb}V37}Vqul5lg}bMI5a4aCq%Cdg*D1mnvaQ~|+Y zKJfNA?@KPhZxm-NqjJ2?0c?|=4`6+(Xu(Q5ogC1%8P#6YHf`d2v--46ismIwxe+ky9a|O9_fBe!q*97sCf$b8Ez@t6Zy6i|oaevk-j?QOw}8Bj98uict3>KU6<+xn%AAge z2N*pKJ_nBGMMhnU>9-07Kp7n4*BSo+_0qg{?>s2vd2b;;dNu-;26$Z!;LFb+V^s2#;e74ML&qZFj{&}fqa3GpEKG4yLgF@5W`7%fk_lNMdKZKkL?Tbk4 z)=Ob0fT+7KG_tDLtZ~UBXAzEbw>VNsB;&6iO6G0F#IZBQ46N}LWSedZjz$XSp51@O zwB%vBcwTc0y0*k9Sw=dOgPaWX9`$a(!?+}uAns9ySWID$TzuU0r9D`cIWB}^>84w9 z(aJV5sS=?D*n^P2PPE6I&gM{x1F%`Qpk~@R$RuPQI*!>L39DDK!Z1E}VyqPtA+g_) z(?92>Q}gDyfL*J{3dFly;B5*r8zgii9mn|8LhGR63*SMl7Wj%8k}El-U-X%>Ra-n0 zfKCDDf!d*IZW1}fz)P8xT4jXEB9X%2gN?1h$?1&oQ^WSFhGbtNNF#ySB9c&>K<~~n zeFsu;S7V;yAh9*ON@sONl?td+j;A;zW7EBE>O~i-Lj(plc%ht6Bx(cB90=Kc2W*aV zdUVA@J*CB{lH=^VEX%YqT{7YpU@}hbgs33#_|}Kn*4hoxH}3?kBBnrC>YfX!}< z@#Z180zAC)!1{aB+(yd?h5W+|%e8X9yH2=yZSq$ZH-hgz$>(BKy zi>VY`CfRM7$PX-R8r~$1HHHu)Xuvy(U`7~xqzrSCN#mGfd1vxbQCG~yT>;!w`i{r7 zK?L#cUp_(QNL%-3sbIx!SXRZg~RS7nkyycbV%FK^% z4b)~o^^G0LW!$BRV5Dc}0OW4K;~D0&lay_#qgRNRq9lP4{{Vd}4Y6eW%-BEvzw&D$ zDCd&FBUX>h`CAszkOUy$XRbQq^Tll#qb$;Wt{Cn7mJ>-fS$cIi1oZUvst_zPG(yryXAZ`Bu4*b@tO&k-86V7x=S1OY%YS#Y%CgzZX=sWl3rGjs?EY8=E$f-1Ot&+>R z%QruB?{Gl`fq}+PHBw}iF4esAWD+u-YLczA}aCh28W?%(FMFfsWE9UNhIT4EM%5)mz6h6?ARFDSk+mw7MWn#((?WA=4az8q<;$ywraxi7a zKp~H~=cxX58e3WmqZP%Cw2dz2R%zQYub}6EeLbnEHgnnBU^B;MDTl~UJytWi0MbUA zgM6fdS2)I32N@j=ScX0KCTWogjRL|HhTVWkC!W5-ppoKshz;nD!OQ|st>yIULB@H; zef=|5W@uX*kxE9x$sx#PY#iqV0x{}3*HjhkbkmHI7>q7Ajmu(!AO_^B66wZLEs`Mv6l_D!DZ+nJ#^OcR5 zn8_Uu)4|8}tCPm^+QAyeMY%bXbc5yg?bEL{oWQHJR@V?*yfJ^vDGmwlxF8&<$T=9u zHL075k|YsJG)HRrh`XC~iU48`LB~$G;;I=Xa;Z2zWP@x9x!TfuW4&!7$ZVDkz|7G% zoKSA^V?gz;F>7?^Wh`Y@`;u(nK zlb*TB=CiI9ViCj?PCVb=HtZ`X^grX8(IkkRY%wr)H09vC>;w3KQXiSvO=JNXm^f~80TAm2uduI9C z7iTWa*gj(quY7S#n6`@o33n{tzF#FnPZ{Atwg!E$bI-j-RdVkovc0w>A7{92+la{@ zj(H!3dQovN+Tn_C-bnFAeDbjsRmTI6c{su5q4RC!mv!^HD_gRmw~uo(4x9oxCmBBZ z=8{$~o@{lky{yk9(#G+sKl(b3TNvlJuWE+o)uZJ%Bn(y5AG{B5f6lDiE`DepU!HB- zE+G-LYmDFnlY@YAd8j74Lp(ofjz~lNv!S>QvMzEqjC`bE^Uq$DGLt~5%EO?NSD$Li z3{U>CIOTvKA6~!A`_%Bal^x1Y6TC3S8f(qFl|gI(aDH6na!AJ_v!JwVR)9@$Bb$RK z+2K_MRf*4Dy|@S7rT+j%l6#|Z9_Fkbn(@rBMCDt{ zh1YbLJ41E{^6yyjL*-11D$5vV-MpNJjGvU?ck9o%^yc)8_YH0rV6^)-(3=R|lbpAw z91q7e1;nyRAi|6Z2b6k(qww!r({AMROR$o};U#%@h~to~PRe$c_0O+8y+u`lK!g`h zEXv{0)cxb%KbPxCG9;1A(k#=N?O9}1xn)p6;{Xr?b?1Y?^s5OZ4J!m$B!yxhWk%-> zj(-g1wkambl_i>U5pui`n;4vDw{m#mn5dd^nXQ5}F{aZp;Z<8FBOQKI!S@v$cW`D{ z57{T0*UORZi;}?SDo!~7kZ^sgL+uwA6321&D@#CCfk>t=8t145ut@s*P?{WFnM&ho zm1&u!+N-%;h-C+%z{l6}r#!C`t3Y=Ig_#`5kFI}SDU$u2V_;+64&+HZ(erxpJv)9B z_-*z>1duHA!5a*j?gKJ54pe6uQgV6qt?r^zu`R8fg2~K}A|oqE^F*r6$?2Bp3Bb?4 z9jRl6OJ+by6m%OUkpX66dJOw_t5(6K^X+4^d!koyi*D|{0)faNfPSQPtofy3BQv`Q zVTqaCk_2RWex|aMZJ0_;J`^tIa`iiq8%+|K$XK7+dR#OAU8*}HW2abo*vgNs!3D1^Tl5$I+!1Twc z8L1Q<%91yk1;mACid2|KmyM%Q8ytcO9F9lKIQ*+(`%#|COK2{&OBtk&Q3^hdr84!v z!@8~*VBo%S)aM48t9^7V?QS&-c_8_=SWO9Oq}*}9qCFJu4YqGo?c4SWVRO+^>^p*7n0}^ZlddFW4aH%hxPAaqCUgCi310 z)k0vZiAdovJNsv_s}1EsQ8zG(SrxMsVX(mD3>=Iel^x_V#b~n0Z{}LhEAN$;a;s;i zdlBe;yBgA-z~g7Ik{g(C>E)OiS*DhJg3@{~T;LqlebPKp%Pv$v8_t2j-Q}E+LB~Uq zY0~VT>&Pz7X9~yWAr(N$#(Vb2t5HcbWfmD3V)B`y4JcfWPjWt(`g+#9?9QZ9Y{^@D zC`2<|s@)?pw06>4w3r7tJP=fd0E6svR_~;Y!nlv-0er#9A$?Ci{c7x&1MG`)3i*&b z7ItXH?b+p2_4mQ5q)9coxV7@I=j3@XuY=GP$vh6H{Bcj(GnF{OlFe-iW{Npc)q21| z1z2O|^ug)JJRfS6B3UFz-3_eQ6MpjIcikH=umd9;p5)|UaaB=blITS48fjx5WC@(B z9+>V&9Zfb*-b-z#!!Wo)>df)6A~qR3=bk!o{{YvhZs$xUu1@9coP>jP4$2C_(6({A z9>CNdKu5X7#LaBLDT$ayqyxh@2Wk3esjG1BjL80C%PIr4T3oSQk;u;nKC}t0ksIw~ zx;Cv6t1?2PBxitk4gn(>9`xd2ibR^+D==33Tyh~?H)F@%80S8qj@1G4Coa;(50f7b zQNClIfD8^e>-4U8)VuQ(=X8AWB$Ji%mDy#DUN|lyc4pc~IXn@bm><@x%PJ-EPG;Wn zSjGaxp?0>=0KfyEQ}w4u6T~h9+s%;*y0CDn-EunceMuetssyx+BfFEzf-AD2l))$Z z=LeEcIXJ+`;|eRO+Qy6V9T>hg@_GB9f^i!dw-!M#2fhaEXM>K7PJxnHV+u@8!E)-X zSatb`>+Q#-Rf0RYk!5T9d#EH0n62&JGaQ}JmOPQrkTIT|R>Trm+rcEaa9p&p$0TVa zHv&8{{`Ult#xMx$)}cVYeG3;8Ev$<(T$`z2U)-co5T`tm^J5&Ihu*9PL2Pa%A|xuU zy^aF%I{tN=Kb^BOTahG=tX)_#;EZED9zA>HRLy&G@S8W&^zc+JJhy2Is5!x ztZLG29PK7p7kea}w9t!-dB>EpfMYym7YBwI?0xGQF7r0_P#A{GMhb#?#(DR~I&e6t zL{Z#W%4LkBq@r1#Mg7?coum%Lb)(ZI1X!X%tBxK&mP!>>5cBCX1vaDaJYDC5S_2_;neXRZf5Yr31Ul&0BY_Dg`b7BgG5 zozl##>hTrAl?7X#po77xma>h0)6HW|6t% z zVV?9y=0!6`=0>*)RdzTbLC#OmpXXWSUfj)jj02u4Fo~{VntM+x?IFK(w^Ef>9;X12ik3-y)nvU^ifQ0KXLwt3 z$0q=ia5(BQ!RNj?CZ!}{DYVPVu%tH&Y}I_xZTqQZw_?*0-*g4e8^1hY9(q%ZZzCf}6iFkhkPs+Q&=LUr&*M)? zrj0{RQW%Viu$NFCMm~qQ#y*_X3lr~=OC!qD9LX3UH>PvWK)|kwUjjOP=MiMEk~48{ zbu^+_ZX{JP%vmrACXqS>sRJjLO~6kv!$ap(K0>)4Y?<=9)le?^vw`N!q`CG zLR-KW$%xy7BQZHUWaW@bO@*K}$z$4nEBGx*bSiIlFH98gXSF{1`+ znFezCBeW;zwPvw5uhez|5gXr##>vTGEzz zJfAbp4RMuFrz9%p@#rfC;*C>kC2Z@%W#T5+FPIkKA`HExC z4tP6Q9m8nj=~>Em*c{s#X#W7bb|l8zm^YR>@!!{uGgC^fIg`m?ZW1sVM4?qwoDX0L z?rPq`izo_WXi*mpjm%hQkF8526F~~TZNG4eZQ_>ISQ!sLI6OM^8&AKjN>8z!qB0{G zyOst8?rl|sF~ovpX7nGz%1>}e`qR%C-}}H}ZQPID$PZ)A<;Q+Gto8oUx+x@0WVaqu zs9Z;98lVS(&<;8d{{W3iWtis!tpq#PRsm4an2oMQ{F* zJ+-39-bet)3CLWA#yR8}4ii$a|A=z|%gBn21BxX?CSD+*gMh|mRLp)z;lWUP8mR2)3 zSoVRO4B&s9cB?5ychI$%@ddhDkiy+SwVjy?b`4aZQRaX_72AQnJf=aU64) z$enFbRyI&_02n(@7|6$ZxheBRcIu2lknNLb3_hd`j-q8lI;hg1=s)Ap6jwqE{=>e2($6K`b)D(mvRXq%Q6=_2>!b`c=gc z$7*A3!g$KI@8WEZKb~rWyCt2xOO}YEG-hcFw>?vA28z~PXn9|O=ZL-mts4}(-{Tb7^acBoXPGY@>QMKGc@10RZ+R510_a# zNBNYDL-b1nWcwnknx2t&meUqdy2CH z&kC%uMGBw{vZA8~+6Nu*IqnCq*11(hDXk6ZXwhKBFb3LLuw^78fzV?=tu_dyiIx;w z%Z5T(O{Ue89rl*U8TB;pw!kMZEX%rEc+ZkR+^g8*s3d|v3T@2qwWPO5-V7Bo2?%95 z$4^i5-n$~wJCm^lsAN~TV{vnG-6x(T@rvJhpL}z9_YBP2qhq#7ImSWidsA*; zFEz79p(9oX@;n^6ob>cL@6Q9@G+7*u@X9Y5z_}a{{TEzgq}=iav_vDsU>m( zumq9MAO5P5PH1FLDjB(qK_;?TLdCq#x=W}m?=6-n z+s+cmtV$o0k+-6@dLDTI)mux59zr4p6!RN?;xIjV^s5&|rb$K!S3nNKfKTaFEsPP} zN`uWP5pb@!22QyhcL2TpN%XBOjW#Waw@eEJRgFr@sO=-6vRs=sE9qnZ~2Xylconit7dU#}QB#y+0Zj)^kKZh+f1#lkNj4&Ue6mn?e` z88r7V1(~FVU)(ftEBQrR%@m>EbCDuLz|;04c0Z8mD+n720&TP$d-`{tA?6diI2 z&(vW50FhD%*I*uOmvI1daWbmOBYLn<04Ljug5{zC@Vxbkkdhy3k z^Ui8Hxm}VjZAA>Zhs~TDSxcmUG_K2%Pw7&No0nK1pL*LytaiJW3xmiVfFzUo`_!u) zxH(v3hFNy`)2{`(43q2zDoeQSBVEzSJd#Hs-{wf7J*TpP&mBoVxTN{7vF5v6FX4ta zU5wJkZO@n?V5H{<89fN;k^cbKsxh*~c=C;k<}a2RPCUW}co&eq0 z-~m=H+Ts|}KoSWebjCvtr=jzI^X>svOvib_#KTXR7!)!NG@*4vh2QKWLohLr?d zuEj^^81McSqLN1FMuGxQbVaE<|r`La1bQAh0}#`X0nn zjFad%)Q@lvEGzbHsX7THmKjV6CIc8Cvh`eGg*^x)bvYoG3$(Z}JD8#jQb{tW0QVf@ z=~TA5g868tQ05sO_OBr1b>tD-=~k^RkV=t9JSyfUkRy{>C&yHX(>eu_E|ps zj+v8c#y~uK=hKn-R1!d`F@@eao+3w>eq}9>Y-H1Bo!&_lU)x(s3oMdMrK5pJ`^}Da zjPxAT1uY!NZY`p?M?i5nC4A1#I&uyO{&V9r@L=r-dbMMll4iZ7SP3V%d zM0NnhPp@!z>FroKyXYLrjaP{Yl2~%c;32`z3FLhb8TwKobCS$}2MjU?-v0pWQ{|38 z>O!}c{{SjY*q-CRAa(kRVk0k-B_=hQ50s7a?mb7oa0#k}n+Ca=a_(1kc@fNJLaj8x zMo%L>dT097QV-u4Tm()DCj^`w-FfObAcOF!+xnkV+=N&r%+Nvx@ z1pr8(38dWexyCb-$^8dzm7~4RSuR#wk=AKUu@P*KxRq6Hp?eN_$JVY}-@2@@?tWZ7kp6tx4vDMiFEx@*J@$ zGQ$}@ovR@wX(5tAtc94E%Z#vR>z?I(x(xQKsEsUl1e4~hL3b))wvb0prDOcN7s7;fUGwV0`MDJEwqfwzs`&sVdXSzsNAkWB%hc3;;^Z?DoMQx!oiEdD9R*mR(ML5 zGDm~ZO9U7ZG8jyD_^&8_k>&3wH!{?b4)< zc{f8Ok(I+0l&LuRfgs?V`VK2DSrx5{_I^c-4JnQ&?kBqa+q7V=@`oH1PI9fmzcRx;YlEP)_}&CUnIzOsw#lJy6|z4-`2I`hThssw_8S@ z0;Cfx?KS};b94T$3~&JB7#ZY>hUHTN;t5`Bb#4_$%%||@10StgS4_gKW+av{Ch43& z#t^KqN~Mc7cs((}=bE7`_fr`Rgk%%tzaM+HMNEJ?q^5QzQr>q_BAoTlBbuF8=MlG; zFp4$hkdH9;B!TqirL>IU`^H0Z(kX#O!XgVyyw2kaJCEm9ql!rFqn2%}<;fdHN%@&a zf9q6|H;tw9B0&Pg%+dljs0W|OeulLshEKCSxrM}2EMZ*8r)cVV;~b0tKRTGrNa$&< zq&G7o+FUa;f23TnmR2M)6VF<$EN>Y|XEJ6WHkb;4syW6^cqh2^KU&ncMM&J*1)5mr z-3Yl+By7XgNFlz5kIdCHf=SAwCB*YhD+_dickVgHG0Dz*b*l)pR)%@Zk@>s)wzrX? zCk1zB10&L}t;q8hM^GL(zGPFDRy~LF`~_#r9qN@3MHbU;s+o|f0GyC=G7q&NvY0eX zL52xu5u1j6%BLA5zM!-nH5O%Nn$)hIrXqDmQ1`dwPF`RJQXkCbojw z*v!T@Sr3rSF>-!Tsx!MIzZ`%u-n6}iN12dFa9&*IFw5n@7du#=)O~&G&f^R+pp6g) z+UpSqAda~d?UwLiLo~uXubDi1S)0&-#(SRB#7*qbMu`(jyeLAs^aI|F$(&W#?BKac zz%wt+6vSay*Yv8fk1j_2%rgX)e|t7qs+03$ub?>g6=L~j{nL*u$jCp|ZH-k_diwtW zGgYFuxw)Il-{nTXG^_ymM^Eq{jbWo(oX#%A>o{4w`)$N5=s}MMaR<_wXDN742&0Nz zvTrzTq#oRUzvEDbXP!HFZyt4R-)XoCP84u{W#ABht~ylmTgz({O5RiBi`G=c>oDJ?q-cH7T?Tei1Up901ikQIjsn1jLSEj63uYf zSlTpZZMnt(8Q}0qKAGTVpD~VBhTUyNtyi0mBiHLoy<5$6Nu!PaQ5DPX18E~F zIt-qDeQH_OMv55Vm@d*Xl4V(!r(yi-9&TwHsWoCRI@U$ru{39SY+x>9z~k%3>r~>B z-Bwk(xRTXnlWnR?APXdzEwu+yKm?zyU1g5Rr!%@dw(hGEmL+6tjO`#0ah&I;9cj-V z#F59A=Hm;v#v2jmJY*fGwnh#zIvVSYQ$~}LeuPpy4~uJdk~J*5Sx5_v;DPK%6-MG8 zB!>~HO~qqZ83!HlS`3m-Lko0J2?(blS#WvC#t5Zblt#2xl&tZP$-2VJAk2#!Zbnkbx#K>$9Y^a%m#(BdwdJsDtR)(QC zhAXKf!>!CEX4@Ft%j|d{`~LuqLeaqtH&VQ%KG7U&3?kexWgO&__fC3awt1|cj9l`P z*tKSY=E=$Zj{{S~A zts)f+!E=@C(>Uw(sm!-;JYgU(g38Uj4tVR4!5BFM=|ol8qJk#@U;tY{&eKkQSD281 zanImt)ahd+l15O=90~ie6NSoy{p=i8 z4Zf!?9C-)HW%Bn&D9maOa&ymKIOp)qOs3O%jVqfhvP&d02J)Y7)^4qzLH;!($+k5| zVSQX9E!^B|`fe^<|X6 zw-B_#WtK3ngS3_a^XPa#&bX~jiIvtxMwT=mW^A5UzE8Dn?W3vRh4-c8bLvnotupXa}^saXC*o?_9knmhE5=7=0*kFtikQ?RT=Q%v}u8Qi)=@i^YZ6vt`lHH{r zG4&pV9!7D{cBaQ{W?Q>=nI^aoy!q%_KuF0uj~#g9(y*JmH>pmVPu@J3a7WPcJ?kXfGs|-dM95M$!=M;a26@lZ01kN-?si&noA+`J!bu9EWA2Rg%~&27 z@>*yTI6}!ha!6Pm&H%=Ji2js9o}QCotGV!3 zgA-TN?%`C4=bBOFMH_97H9Qaw4*(ARdz!oAofYlw=JFs6k8G_B$Z*-{axs8<^*)u8 zp!l}$!ry9=;DHQQ=W{eFzFQ6ye7G3oWsf|bwaYqulSXxGxv$;5PsxAU!@^JCFNr$M zjkC!cYI2>{>5~~_ft-%`C-XJso)J@PZEbC1Zxd?>pk3SE5*1^0#AgEpe|R22^u}}a z@9kxO{{RUFwl&sh(&pk#$#IYmmOk-T?Z*InSCRM*DC3-zUoq}gTYTzOq-=Bq^*G7= z>+(J{r%IMKYAVg2(fm1x#8%-Na;Te{(DiQ&z;r7+IqwaNwtUOYv&B4nk5D)~0y>a5 z?OO5ZS9iwd;uxY$Ij(+kqiJ~Co}6QzIOB?oLGaYGY`nX)5X5Fs%;}jI1n@uEZZdwI zE3Un}xU`mCA_&a!NXo)nT!mCUS0mHk@I2ST%MVhLS6=Dx*}UcLUoPh}b#JF!>DLxE z)+Unt&w8Mld%V=~ELgimuFe5XKT)QnAUmYOmmXnweJQTWWmD z=2O_@v`+~~c`cOCO=xb+YxbX!u^H#?^~fXX^y0pQ@Xfb`u5`n147W0B#&I3LlKY|g z2@U@12IJqpG0&Ij_IH{Tu~=#TWya}MNeh#npVqxIOwxYCq}=M8gKJ32ZIdBmQ@aGP z&MK-FCTu6W5_l%Adq_kZFU$7t$`eo^_t!$d@_)09p69ZaqNH9fl2UogYrS z)Ahd-+)iM&)2H1mPZ(I?WXTPmPr7n?VyWo2x0m;}7v46C{ws47-`TfT)2l+VC_G55 z%PHtU!5e|?gU?<&Yd3m?_6r;~u}D1ic$r#GdJOPE9^Z|6O05Y}_fzHkPcs`vv}Lcw z-E4K*cE2fPm&8{A;Ezvlu@fK*w>kN<&jUPUbL?)vX#5CJ=Yj=Tzd6E{u1#m%92RZ(fTt*UbRE(!O^SLZwA5Zj32WN=oAE8roc1ui4zi9Pl)EX(YItY3SG-?QAzArUrTD zzA62qyhmqer`g3aPWLSlQ6e_gUz=)xo~OGWynRp7xBA0eq!74hTFO?6*JLW8qa)`9 z$0xQFLFNi;IbbA*^p%O1pv^cg+Y?Jh1s&b8+qUL)zlv-`P5G zcAM}8miu*(0w}NNCm+bdZt6J_WX$DOxT+bEsK5V~bF(hYpN~a_h+q9B9|KerRB$AP}rLBdN*j^sm%1xu-SCkC?YC+1DLJ%Cj*H zHhjKHrdWVBgN6EMC+d6FOt;p8MYkKC=4O!GJFt*3@5tjh{OS)7%$9D@apuc8-s;&5 zzx>_ zC)k6>7gb&2MEQaC=chyYS9hgF zC!EhMyQE==+_({$Gs!vUa2}tHbkV5ftSQ4*Y{Z44WsD?p6l^#JwlMYRIv$;R*20!p zy$K7nhTFK~r!@*j*=O8iLnrT-95=tO`88@7$&3c!m$_ot=bRJIYV{zSXDqZO8yKJ` zsQGvQ08h%Hkrc_2Fj;o7RpkEwpIW#uIO9FIqXVuvuCHS&87Wzr?GrSc34Mu-C?gH@ z_a60PI7+U@o=LWX8+HS8?lDq03~)A*zj;XY{{SYGCKM?9pkYG)0CuL$70q(GeBd)F zR6d^F2lUNOfCfBckCb~-l*m-i-8nw>B{)Ti%IIhW7bTg4Hb5YJymTLydG)7JMRluK zfTD^hwtyfQEygl=;+NW(v7$4wA}dPSk(GI4jAZ@-pIO?=U=RR59;Sc*=m5`L3T%f9 z(4Kn=u8kud+dQ$312;Wu2~@PKQddOMA~8pPJf_^IcHhpV$T=Rg+$#)%2?wb46y@pn zO7eI$q%PSa(M2Mb$IJjeigQ{@DQpFO{{Xx>A2voZdw=@r@;4l^n9mKgo!^~DFpRd= zA($rSP=0K7{-U#HG6zp7en?~#!2K%P z%&b{MjP^B*B)E53B##Jju~mx>e+-ZCsZ6Sq>^oJ}Iz*o#1obD^x4$)s*F>;qtxJNsetV9sSbH+zwR_>z` zK`vHDER4QfO|_4(J&(O|;^DSRJg2n^GNHcnH%w$;S0#7LA*PgGg>6*%W<`r@N3i*W z_<_&$Kj)g^t}dD5{nijdz&v?52d_@!-nu)B$hONFka^LKu4G~Jw^B*zpQjbW$#(FY znRkhqgKv}!mv8SL+4@%=gm zjC`OjKqtRS=Pq>#t&GvztND@uq^twX3NU_Lj04*vx3R37>&7xF&Lk3U`Pxnkaoll( z{xuF!Ph(|C>7mz3#bkKH20+D)?6Df!*DH8(< zuyt-1Jy-DQ{HZFOuawSlP4ifr$%Z3sE)rP8C(X6Clq`y)>I#hW*VCsttI$Yab|hJ% z*g~Z8ss$c{7|9%vJDc1lPB78m*3UARkZ( zt!tJJqFBn|%WjJYsv{4Ax3Vb zipN%vNS6dCiZ(3KvC4)Xxz0fM{A&HB)vffg$#W7*brg-U-9t7BCkjs>@INZThRx=b zM9NVYb4=_Hdgyfh7UB;&P^tIIqlF}a>yPJIHOkJ*!84&trjkh@42c^?1ahMlDyOIi zf(XxF$oH))dE+Ya8>hIs0}&U%V7zb-ewpX4eJh@L;jxlNw~9ss=8Mm`b|s1ViQGx< za0dg5#yWyp`LaB&&E_bHRWiy?OnQ#w{{SkLIQJ4gN=ty#Mz*cyBMrG=JjQPQJ?l0} z%rh`)Rb!Svy2lx8)*Y6j@yWTAN(+xMdECR;_NQLz2@5m%0%=qhnKCy8?ZM-pUuvkQ zDHzT?&5E~e=6#u^ks^&*qD_j*4tVDS>x}oUtv+!SIhNtR(RU*}tYjdze(~Hn{64<5 z#I54oyLmB@7zYk|5%vC+B8dVj@{LR~?wA`x*Kj7V5u zl6^lMRb!}OO4_*sR{54j8&vnMav^%LeWF*7$}A%)W&%y!N6XZYe%yN1OUJ*mm121k z7)UB!RXA2Z#gU!M^s1AUhZx4}+SH^0KE%YjPZI}dDrS?)YaxocXF*8 zs_u0pFJgF8kUf9E*B5=POgy$}BbrT&uOhAn;pyKWT8hH@O*(X$?#y>YG-0gRw2K=8 zJ7DrSYIPN}E$9n9wO&s6AuWU+`ah>52w*FmG<~>bZI&ThF z5(oUu3&-R{-4*}ns|F(~*DK9|$LNyrc3U|+!IQWBik}4Psr3}Hr^`!CT<`Wv)To() zBYzA>+jP#X1-EGNc3KqH^ymw>s?f8d`1($VLKq`kMvo{!iDPaM&V))7;`7fauA{G5 zp3ix6%y@7AR+I6?1muqBwesXjB?=q07Bf3=EIwVc{4L$z8*KdiEu6$nBdgg0{`r?1 z4bM}e-(z<*ZZ z$lJ*+HoeuR3fNR+11A=fxOK6oBrDjmwuR8koAD5M%=72vZ*W|DhxN3hsN!fM8u=iz z);F_mjBVAec{ckX$)a06Ci2!uKMhHA?*1-#&i0{{+l|Mt9XwvV;CMOaw|N(%&zzNj zJkyHgKFi{3GTuQJQh_iz%bs}&jkGjFfTEa3n?;^7EKzbmpfeZ~X0M0RG7Ep#zc;kI zFHL_qtr7<*uIq|ueomFL{!?$p`xZ$`;d(-MAo8|dr+3Q>3T>>S{|?e~md*jI;KG9; z@@Zi^0jJL$$5^8RWIsyLoSdsg)|D(mgwS8iuOw_X!6y!_rZk^Vf7ymD-YRs^O|S1o z9ruh$To7iC2~|eeo(7-KGr}huPbV^T)%~u(m``H;&@*D@RNLV(iy7!de?YdU+Uo{e z{JUw&8H8;>8EZR+Q=2WrcEKE5r2>eKc6&w3Bi?Rnmws<$;OXz!+qB|B5=M~g;W~2&xI`R$32=oi7`BYz9G!CoyecdVP z3j;0`I)pe41bFQ5!apZ7_^>z5~koWp#eBrN ziagf9A}`-NAa9iW3=?t!68Gh)nH-~h`m{c$L{30Jf-gxeM%e@3wiY6egbbkiP+mH#`b&$32oub;_eA=En!r6Q= znl`BM_s(KHDv-OsCoUIk;bZI*Tl6=59A)BVPPOJ%_B2x9J!49kBpyw zbD)9n^PHv`_5%Y0cKgS-={B%;O^6I=A9@}g2AitCKNHvE7Rg>tKNWthm0=`BUXeKt zEJok?ab#8R(Db$qwCX4EC%wj>VY39c^kLnh^_4HTq8ul&bnDUE@t(bCqI&VyGl52n zo9kFMhv#5uwV7;q7Vo>^4YIS}QwZ%|!Jd|c_7|0*>H5oEL$Fok%f3)GS^{7i+W9i2 zQdLo(3;WnT_);UqKKJo=k&aX^5fK*IfyNLqz=;f)LAgN|Bo|+su_jYyH|CKvy1!Dm!p`vH<H6USHDhlaNMvPY>*5w1h@Bj239<`dD#5-l*+7%P()`TMLPi zll-bi{6T%__RIU~i`Lz5bDzk02e!mkZthSvGpNKnqGNpiGQ!%9wE{-KhnU zl-C+6_c#=ktGXNRKIw)#jTbO+MBZH}^Ay-Yy13>XqkpOCffraO@9qr$Yz6nY+1DqN zQZMz2(#f(wO@d$G<3d-hj;f`ERv8c_degh^{IY?TB0ujIGRxI=`BM^n=Y$RJ<9jDm zzfN8>q#%!a$lWDRZkLh^!V?V~WJwp6K2{Vn)?W_;za^SLqrifyuj~hG0LGS&v zt_PN^(;Oc6&m50T(td}K8kR~b=`^T;ipWKJL46q++27t84;@YLZRN!Qqg{&X);GVv zV0k({nKU$|(f*ABEUQkin;x2RF5S>l+?Dk~@UT&oXV**DmyQ}Ti5&%DwEsSHYGmkv zs-5ctfaPwC_b8#>Tu_Fc-=FiUOr=seSMQ%(oq$q!kU)1ID!%AVW*p%3z=9kRzLY(x zozU#4*@#mMj=CT&VlQSY(=)@^KV&mY1;etpzsoRcWUXCRgd%PpQWdxufB@M)oWutE zhll1xN+uuP9mO-{KgI;oY*UgI|4aB?>L{22ddso`!a%L^+S584;*Mj8N8+3U092M= zvXRoFm#+=}?pva$L@a(c`LFNkgaAD-jUr8p&)M+4(`O~i_cK>+6YD`%@QR!2kEB^z z!6~cA_DdXuD%vKJTWq~Z>~h~NgE>u8mHfJUlOC;N`9KFUG>$1Y;Xm{Q<+`b$`cPtHhXAfk z4d+meYXlo9Mh>g8AP-Cx?Ic}}pjKJEs33J4aBz51%n5_qp6o@cZ=$cQu-ogdEVKBc zylOstd2tBrSjE^N$H8$!p|}z2!N>N~U=Dydut+VmSiSvReLb~wd+~kY-w@v*U|631 z$qaEy3g+M-ETjQeq~CnyxlDV$hE~lSXy{k`)z`teg_FC($Ro+2 z@t~rZVfE!+57x6=t2Lst$nCR^jBeN?k*EUwVcE~c#S{iE(Z8oRPxbmRgqFU{BF^nUevfi=HUQdW~!=Vbc z0q4-QoNgG_T$#UjnM$&(;rx0+y-0M|?1olGb=7C#SqsV%Brhl6c;>f9ngk9(U*Rsp zQ%p}yx6(Ef`d7mK<<|+vC>H&mUJth&BrNWyvKr1f)9{1Wlx&>|X;HrEAIcg?BBwTQ zDt;-6XZ{yGlNrX<9T_k$mK@UeG}Tj$7C;1c*!U#v3H}*YETenzI3;kW2l~%O>VWFe zmb7`4f6v^F!rlvh$I;2_!eK>!OZSi?ATFn;4Yv8PRo;-f;6E~E7fJwWG7`2?#<2@> zs!YVNqls*#BWNws_Xr)DIAU`W0P5+E;*`?gSaHYd|CVINs#4ktIc+|1;$j*K86D=V z9B~7ayFln6KmPi|wEsOdb_~EU->w?34C+qhUw(uaxcp&F?1iro!3Of%;KQoU1cqSW z%v(76@{ldv7a&@Q1E=hFm6F1pF23@-FGyPSLvbfp%Zl5%D<$0{Ku+Rn{o^dX+W9V_ zrWrWsbiq-a#~ABsMfvNQxv4T9_}Xg1qQHO_ttEi9e0m_0q?P%Krkbw!{G7nDn@Frw(4J1bqTMN@9Kr07CfKOMel{Ejc4 zh{5weWxsE*ShP7IsII>!d!szXf>IX@ERQT;BN{oj&PP;H*#vu9E{Nq&TWPSwq=Ch z8x=CSVD=cPVtr(~?W>>2kJe8Jp*a2{({KzL4|$Fd?)9}5GrS>d%pU($Y!Ro{mYwMw zr(oTnPogN#R~mD}-%#(LbMeN;LVnMjETvw9dN*KWaulYUn*ubfs=(=M9IVeNsOS9 zZ!%eE}=VA9xEH+a&@ z44$d#u=!{)ACmgurdRtu{&k5-aFmx)zivi&>e5NGb;NLpnJ8orX%eGZ^?oYOI!j^& zP;0vf$5~{W{p(Pc10f9%{sL+D3+}_)$-2o>j^;{yPXveLnc1WcpKo1-NCSael%K=a zEJEUjPo7=8?GDoCl;lTzEl<^up}l(vG9KH$+Os)cqWnyJJ^i(DSPqGxOo^Ad!VFVu zC(cKs|IECji>o-;V8MZ=$M^S*Xoe%0z{qor$uiycYgOv}k)n-|z<-~|Z?VX2y&6U) zn5iZ1rWZaL$!@A8ul96NeRi5uLApC1KIogVd$Xn2`&JIPRm85Uxkm%p3>BUKJ#+uh zWJJTVPI#NDs#8aw?MY^yt-dWK3dMR-?7h8H;;Sf`S!7a3Mja-s6P*PC?%LcJK)W?c zbKI_~^f3p#SGOQE%b5ML`IY{%c`5gmnT)`*1NV}Wro$I);P2XtiHNQ0dE$hAN20JbW+~gQ=L`CyXW+M-4)G4FWB7zJPD<#qwGRj z3iTnhlXRp!Qay4c$)eBKenvGOmJDNyU?uiIpOGHyR?SuL?KfKOi6cOscS!V3(c>;Z zUPsaJB$&hfbj)ekpS_YGqZLw1Won&)lZotX5Ap+ZpySBi!^{zi48gc_b}IUqNpcf2@FzE>SoU z4I3;D(5LTx>rVQ^B7A)nJRzF(tX^57R*}g2G$_@ zm8U=cdpcaLfYv4pz>FO2X8x?!di113@g6AMUcdeo*!_GsYDb~GE?|tC-4%*R)!vf{ z-@zhLXT;yLkQEi}+yg}cg4KRo+|*N} zE%`*oV!(#EL$RuNSK!JxAtsK$$p}yY|0Zk$a^ur>BEuri2#*G;(NNtfy-lQKfPwk^ z1@GS1=h?>7^Ll3s+EYD}6KF{jFK zz#k}Au51nO(^6(9PAB1%FKf&4!XnAIvKn~u+^9EV_oB@2gDeY@+336?pJA18bWxPA zl%0QLe(2aLaY;%rLLA79EC&R$c-ubnMNyUnt6UE0OPk9X-*NAiX!jvoULhBV`1k`o zYaty}bnTz3xc35va#L3UkWn8lH1rEb3FnF4ek(MVo$JM$xLf+VN@VJp8u@yA-U0_F zFlpV!J$npO=@oE@Uxsn<-y5Z&oGWtIm?u8FUm=wtXkRW{oPwje=FVH?Sayi?W%!9+ z*Iq+r&QX3_t-Trd8LNK31VV0i`x9$v4nq&`=|6>x7rEm*s`-4Yw612*=gLL*=cKuk zaxT>D_}Z~4?aM&|CvLuX#$qcuZjZJQoRc86##oqex>G^ic*_&}MV40T!|{cF8Wj2W zSl_n+d3d(qHUmj5#h>|NB9Y!O(`V%-{ht?q&cBTS+{_ zhs_z27ViQ*$v$6HUpkw?J|l#4M|5s6Kla@qtNy-jSpf$XU;N)tsjQ(Ekw;QdI*-w& zWV~|cKWxUNak?(ca9fVdTbwK6SvgDCaTqjalhqpItvP)q0Bvr%K;+un@rNO^6ORZY zRcQa=yWKjRgz=UZ_pbTltJ&@+LG0c+gFk|K#?tbIk)x7Kk)(#hRL6XimjU~1uO8J0 zxu(H&Ez?_JR|f3t{TzGQx?|i)?$#32vl^pmeFX6-3MKV}#xDuXPpf51aL1KT_p28r z!qj-dL#0{OF z)^lYE*nOc;rJPeeDk(3ArwVE{+RWv9X#S~=>wq8-Gh0B&k5$+j(CZr=aHZGf?K>E8 z3(+KFQ6|3HwON1af0N`V?f-lBMbrK2+4btv=}hDB1}~+ewOY6k_Lj}5w{M(7T2KP= z)TKBZP1fWmCKlMzT7(I?u)MfJX@f{{G(_Z93cd4Jj|ws`}#DO}d;!vrt+CI+I% z9HIWP4<0T|SQdk<(W*T`s3|AkF9zWJbg|d;*n6Om8f7kC+Byn(E1VdifNR_{KP2}@ za_Pfp-;CUs>t4R=_QZmA7i`auVlrCwk~8XWh_H*4BISo-?nye_YnKLlH}?%r8%VRU zaT~E}AEj)0Uv=pLq56)NKI;`xQGr0h>)oOxd+%qO+twiyBJ(4gB>C?sPl?B6DRKQpD zjii|dq+yN)M4`Nv(|Q#dsn6aw3A5QLPAoqD_6G0v%q3Vy!bBwepr5{{P9`&Wj+V}d zWl**tyiJydvN(dM@o>1g*tEd#p^&8VR=iRaLo+p7aBm30PB>+jTk%Axn_uaeeB|SI zwX3t*(g^{Wjf;_|72*+H&=P?YdOX5aKNpd`XM4KXR_M)B*;52eV^8}Ogh+}yuUt)j zq>YeSNM_3E|JPK#beTA!e7;fU^xXZTFsQu5jyb5%}LzN;}~6Tkbe%o$J4#cU<%uvMC!7r3Sz}JOWe|{gzgXC(?NMR znRnX@rZfjmjAQXYsV|%qjiPV%;Cwsp{p;`gD653%45D0|>~krGgAZ#tOy0%W?$zwt z9#qSW=3frSd`%Meili_A)%T2U{^@--Y^u8R&cZth!p;HP?tZ#m!dVbVheV+ZptCQ! zh0vSeql_Te`;(hDZ1EZ+=bX@)iHUc&y@l(_+dhdYNx-RP+XcC7>$AIZ5posyiTcLc zN&B!p8m+n7f4OWi3`2UJsiLH6M1mYSX*^M_AH$ckK#Y2g%7Ub?%9P*0j4|PkJkEfh z?Ep*Lv1pHJp^jAX!9ZZt9+6o_HFY0Tq9(ia+cs%13oo@A-RKzhVSJ2ZN-21#Ak3M$ ze+~J=W~0{z8xv8ahzhik#kRV>Q_XC0=q^&$xv^OPMP(VRG;VO22|dQ~CI4{hze^EM zYrXgRn--I9N6+*@a+KxWw{nsm$=CgOuJ5XV-?LS8^ku=xk#2Cp#5{5O!@9ZiySL9n z(N=&E-60*#H>nR~3=>maRAZxyx-W)#zfaNfP|?GhY0s#_xVFoj@v)Fh(>DuSKc!2ltUD^QU8==|Cr3o z5qO0l$RE7=7BeLgcPYdnUmdB3@UO!|)S zR&@=vw~{rs-mu7}EYrvWM5pVt-lq+;`4BnTSWUqJHduWylhU+a4 z*hwaAi|;>mTNdXXKb2CVjDfw6^PnV4PRyQPJHMj7avB@wJld61K zZwCCpxluyp9~j&^xUO5{fmo}@&5^RNH)^}Rg=U47&t@$Sh0`p`()Ct@yy92tNw4^t zOtZ0fHbr}PQY;xsy0Qn-ae!8hq*NF_dd!}xNV)TO?MzvD*!K%;biq43O7Kw|K5LZeLhWa)+Js+~ zFSlrjm=GF9T&ybcy(PCsem1EZGYb*!332I0Y3@|Mapt%!YEqGi`6kNSVEC|gbUTvD zRyM%Ke%;I7l@5`JMP$as`c;ife3NfA^wc?(_q$0JsuuJ6I=#?vzjn~0*U_CZPuD`s z*Iv<{p^%h?d~H-4^k)^znY82CMD(=$i*NGQUvK6rPyu}*FI18EkBrnU<*e?s5o0f; zC{%LaR)2C1unm&dGyEz!(x2AjUr;Dh|20`sFaQ8xPP%!h5~tuLUUA|Sngv&w=>F!- z<%Lx~2_CN`>+PWg6eFi9u2q&yZI+P3xN%o8PauH&*G|bFi!kV25S1P%f`Y)xRm5)okU}3>X4gzy;54x<+G)Uy`CXbBlP&ZVy^?N05p>&U~J6Wi+ zBf9r)Lfu{)g&emQZutfsI#d^JRf6wG#XmdIiH)A&vb^}IpQruf;C3*KEH5DN2F?l< z3Pm_sT^817w^#_WGCzF+m8<^cX&FJ9v=Xzx5a4P%C`q3g7C^!?p5 z!Gig|P}Y*-65nrk8|&nkbl7fAMq{IDSM87A%7xYwoA4Hb5A-+cVLM#JYJ+zH-z$?2 zjlCBi*WC$znLN5;on`k+llL9rmrdbe$;Q1lV_P2k;#T9jR4*v+V93}sU37?nW1T7< zAW@aom!j!IbQe0kB8%izW!<&qrSdBjv5j0x-O^HLd`pyC}C?46RhTIE-rog8d2!k&NT1a*}Pmz=NpSq zyq(m-=xgNFUmqR6?*#OQBHZF22M&~Rpv!pm`+UN&Am3ehI)J2j)z$wR5Pe+QWDq>1 zpFZqllYY>3QwTINWJ>OeqQnoIB9@AB`b92Q3f&jG7qz?s{^d?pj8W3%tl$>wQ}4D6 zz?o1cTM1Q}HZ;u!Tz^!iu(wAigqj13qkPQ4YkX@-H;HBE)m5)fUV3=wBz;rOJ;BxX z1JbdcF_9JVt-X_;^wJL@kxQ7w??`N1!6jj(b2CPCIpcu{t%|Nd61bn_dB?QP>_9Jw z>21*Tp}=fE9VV}+mf5$*OUJctJ!rG`;n8|Lc>SS|EhQFG$1B*~*=HupL6QX}Zw67F zJ?LB8DN(zkD7OfIhpysy)>Kto{c8mno{=9KG`a(!i4R~NR#Q2zZ!!Mx&gbAsoY`0e zZH}D8j*mN9v1L+20^1+xHZS;=1w58!&SdifL+Jk3QU67oYidhoB2@8jslS|iB3hGl z>G{sqdD}-mv6dvkaPQ{SytIRqa+O)4Kr9=ywk&h;n{M{@SSOD1ukr;j@ftNLk#o zzHt~=QTsdAPvLD$4E`ZYV}#y+WRYLa0svva_j2duOd;Mz4dM;N7G~?nm@*a1&Xo#N*mKq2t1&uDjf$mn5#d1MFN`Fdta*()XmX3;YQQE%m!CIyt`e z?00E1qx_L

Dgw67tWt_t`tnq+`m}pC4rdvfmLCS6O&}fpngjeCI0^=^O>`W+>?I zCp7z=%{}y9C6zYez`t|(v{pDG{<7Z4|K8F#%h01BZ27x)qcCnoQ)G{UgaKkV)6wDn z!V~P0r1}+yGP_1Na+)U%8VdO9uRy&ZV-ahVmq9fxEmFu4xlj>Ul@BaNPOEq5@7hgJ zP_oHsr#z_^8Uytl$}Lr^)jNp1MK20Xo7I#mA6&EffS3~)Xa(wbK#1&N-v_Dt=^%1lfH%U2oOQN zp?h-5R^?P`%%nxAQGhyalDHD-EG>aN%fi^ckU8`z$S)s?$PopkL~F9>am95xep3CAtOHsd>s>UL6s_K-RG>2_(EuD z&F_w=I_O95l#Z5*OJP(D=hgkyMuP_M-_5MLk%XSA3~7E#o1UK1(M}qsfm-)c^g)uA z)yIBPQI=i%;2TmOJK?pIANsYiTEG92rVC(G@A$&WWGq-On85onUuGP2ySv}U3e!y@ z`~v}uI@47`mAkisgjc8FH{N(jRfFLgsc_|8lj%o8-GRr(!{)keCb?2I?^ki6#WM$? zErUNxrP>c4=L2$Snh{5f*;VuYFLPc#38+0O?S{_sN0gp^eaYP}Gx=q74~OZ&kDlVx z-qpcc(D!5uR{()o^l~g}YSfVrGX6 ze>Oc%ZmO?DS0r}emYen5$8L0}PczUws{bRDm_*Z|Jt#4}OBG}Xk}6zgh%U)xb?P-F zNFhF8&9FS2xA$XPFm^PfXS|q@?>Y)I%^;73fCfN{ZlcH0?nyRUHD;srkZ=Fk@3^f3 z^|rkJ{H)>Udv3vtVC-nwix>*+?1Sm*;MlrW+#^ca2oBq=HmMQ^*;-!08-nPY=Gxxk zb9Jz|Yu<*h+gl9tMv4)Xh1ymfH@9qEVpj-dHh7oRdSwA2J3Ndx)%bnxIJsw=XPvn} z?MPtG=+eWQ)prFTrjLn2l}glb0ap%ChFxeSKw9o-ssk0OSfy93?%}XqU?TS^!24>@ z;_8J5uQCWxLc1?_R^z91Q^2R`abBK?1dnhR`J`EpX}m=FovlDZE?AD1A&ToiGNBTI z)L_qavB0qjkbfYR6qT+!O^Hk_vV_53d_|2RP5y1VRAJfbr6liQR+>;}m?)BZlY*R= zA$Xps5aQ&@rZaAFcX2se1SHI5VC-JUIT>|eIU(^WXc`Y<)?vaI%W%2QsrNCSre{v} zc2mFto0|g1-94%X+80J#p753Q@Lta@sHdu*3Z;kUiC5+ccKUW1dOqqKJc)0j4a#R3 zu}If+3!I_{0Dh{MoCAlXNf7ujxNePfsh1s;_ znLBAn!^zFG5>#xTFar;`@`V{Q32g+fs~NF5Hmy~ zrl<)pZ%<+5fBoyl);%nv-e@WTP)dri?Q-hAiN~M$9O{2H7Q${x{D z764kdRbIcx99U!i#96;#lHKBsY)P#&_i=y4S#O0#eCKsdAzd%6Wha zuNmK-_^JsHY08$MF#8bn&flY_oY}c7IK{KO>#f^!SzFq+AR-E_o{GKOg-RS7YS9gN z&BykJ=CE|*MlkZ6x1N^%ieYMg8P`qGojsY+QVdu(JVm|MW`xdm2Yubxj-9jZL>s%^ z(nR5TSYl3s)vh*r>dhnMb9kRQ-V;8=E(#VNyf^vLF3D)7LyGt(0mRURgd|n6rP6-dB=h;f(09P`VB8s{@b1}DP z(n+zQOM+6Vh{%)tlX*UaS8C*>B~>G2r1UFR-Ai&7i*0!+N(x4S^O0dK{&kboTNvr< z@>VCsgOOv`e8Bl1Kc^h~WR(M%KBJyHWPHeCz=`bF4tP6rQBKEl+OrO?B8myBsaz&D zE-y7g9E3lufkoV{Wr7JS-qJcdEu_GUpOl@ZoS%INxxe0R;~vN?m@KnA#f)hW1168G z#VN>#I6stnG5PUT0FF#L<{$q~(NmL-?mdw&ZmZF_UqX|2cWo1j3uW$dZFqg# z8Mi~;BTsNnC1NI(%R#vn87O}crdpJKO{zAALD>ZywKmH$S`>Y{Z#s83Mt8C|mgY)_k@WPC3Kv#v3*%;;Zb$8Frd$xd^d*tkZ2D`N93)HXfo6#ihr9%r zgF%QYT7&y;fqd20$0Tt|IF{n|Yf*)Wbk-yj^a*gVi-Hx&mJS{2A)^*8yD1Y1Bo!fr z9eu{_=uR7qpecdn9?LDo!H8k~s2`S^j_~K5Rf4);sc`Z{z6V-FU>W`+P0x944Vtm7 zY5Zn_jF4ntk0gFAR_#BsCgf;+-jhxp-!M>@cu>D_aM>p^MNDP@SqL>v)!m_)klv-C zvK*f9f1toGdN@ZJISfD4H-$rduX}wEGiO3xL3f9G;@f0hfnt&ZuBhnZupM+<2j5ag z%OjZWhNou|jZ6ItQ{?W*B-wTzlH6p{L!vUOIMgi?itOKReDDlp%`*8D*RE8YUaj}% zFYL#8bUCWj zoYBgajFC{g=S zpA+R4ZTet6s=76*1b)uAdX@2RC(Tyj0rD~=8ckZbp&Re)LPrt1(%~#Ni-L3x5#hr$ zG^FBT0Mapdq*@m%+_FSM8V?S6lm-sE{9Tq-_Y6>k19@WixDEtUeLYJ!IvK%ufwToj z7>r70G91fjF)ZV6Jv(XVr3Xcd^&tb*zUAGy!z7VQlPj_O(|~Gc#@1PJ4*X#0=C}(J zTU1lK`|EYmN`6ykPpU4~3FeC4c2oBuF73cH(vCmLI8#Jkm)C21_T=hMbDHBsuRs1h z>CJ7|dzGg=M;qxoDoewukNCK(qPSPc){G=V0+qJ?0 z-h0&FA)It}%+6p^d_fQMHKfTWY19WWTklH_#c7pWBma#CnX9;mBic9F_ktsLmS-G9 zw2Lt|6}O^o?mHnnoyw%-J`&z2ggD&(G?-4NB}DWPG+lj3M*MbO*EzVcskNhf5(Jii z25r@vL=s+~)^V?aMlZU|2@=pkm6$hXVUQiPJ|p5jCbytU+RM5iZ!{n+Cygxa84C-^ zK3=&|7E9b8%I!<-w7sEzoc%tw<)4WI+NW8V&RFk(h*W*0BJl`au<;^@XWT*PWkTjr z#VH?>#6sWmi`lmNrL7BheKG1Tso4ixkZN3sf?iwqkG9`>v~Ad`b6WUWk^|tLq{Yd< z(OKpwib0U-q+|xa&kZ+_&DzRC*qGU`olo zQs#V=_r8r$&cw|6mN0YQANjg*zrIpk=O&>B8tb#LHE=qN6Is`?5?N!I9^o%F^D{E) zA)=m@p*QriJVlnani(x`s`mbjo>?5unF)A~O}pjzDpB}N-W<4-+%w>3)DG!82_u-$F1P3nR0@`HqVwxYlX8l*qhRBcG-b%0cu<0y40wjT)A3m45o5l zQxDyhufLCXzI0q^+G_8Bd*RB=DEknwg=U!2 zSL;#RE6&R@2otJVwB4te8a)jXYm8v*3!!a*sII+pP8}+0B;2 zh!BHn*~QM}2ysIRN$twaJ0t&*9Umy#c(i8B7tBGkR%Ux6)^<8fKv`{9>Cky>STJy8 zdG+Zl!q>Dyk8svMKlfKa`f6290LEJN_wD1avPU8_3ju~-t~?~Lq?J3T%o_JeN&O3H ztLNyUILtM+8yRxlJ`clE1rP$woNVN%Yha%4Fvzp$$8$2-pV(%8FNt8X% zG#drOAe@`Ty0dEG!H9h3@_Ku0ErGY2g^dPEwv0d_kF2xx5$!%h>wQ zNr+(>O^MkrtGnB`jO3N;H7F^UK$xze$?z{qneMMY&iLA z6OCA`f*kuUpk_Tb+B0__35{nwh(hb zPIcmM8zhxdD^H4c**~ABo}`-w^b;|2IstRX`ajkKHOVehc^q$H5@gQ_R(~46CKuyx zv?NFJf-|b%5_dEnKr~*8i%dQf^)M76EHaOr$*~_7l3AG#bQTUz5wGLeB?zcER zAp+>ljYdZu;i1n_j}s{!{~g{FXv|OyvG3ftDUg^zEn9qQ)dtp;cGg}a{lGHAlvmz= z%Rck(PB19xXDEX|7i}+8T4PAr1>0LivVdf?O39xK!aF_sc;8zHsH9rG?!YK*IdBZR zMogkB(Nwz*uO3GrSr$4kd^+E_kUzvVE3+eRkG|6S6B6{&`RCx}9}R-zkRf3l?Q|yR z$`StAfNgHTsm>@cC4W1BFPc8?K`teiMRFxZqL8jp7-9o#j+OW+39$2V;la=~Zjsvt zMOxvhTmZ*&uSE*7pm~VVy)TAt%g3yv|DbW~t$sdeC&dS;o{{N^oMH}@NG41B;$^)@HF5zD5S0q@nt~-R{V_cDrYa!{;J}h15AwIh_Wc|B+Dj z=;(&K^dv!PQz;%djzVbWN#E6Q?QzqW&9)@pbz$J5QV|5^>G|%a%!=_& zfGXrM0;?Z&an>YBs5dwu<}|Uyu(VE5VZgu zS~Od6Mm0p2>flU6d*v1~OH@@gxz{6FkXuW5@%t0WC>IoF?&n3#f(}>8b_U9#-5ypI zF9)WaG=&gL5Wi>JRH0Mjd!Q>e{(K4eW{G|XBj5S+O#<+~ln5toJY>=#w`b{up@Ivv z8P1kyP{<03^BB~71bX%*mrh#yjT-F;FQYQwud;>B48c6&gntO00vL4blr`~Jc5ws& zY1WzUL0%nR^yqC1Rq zZQw{%?8rqU_sMG5-zh-f!Xn#$WcN;wY>HM;Eo5*wPzvFJTNTr8G$965IV?fmtv17WyeYScmh zAAk8$_iE-Y?Z%DOmER++a>G-N4`o37b5o5U0nd|8$_#?PNEmeF1GhK{Ky=3osMoTC zoOrR~7Xb@wW908OhN#OwVNWuIaIEcQng^{GOwN@3V+{7>OFz)n^>8P5m1gHfW&^g# zy{^00!H$WJ~7pIoX{(qrOxuf@Z^=U*Qbvv?GU|h&Qe;kjzF4IlQ62_o-g8WfS zuMXQZ2;($~8|e*IHDZ9#lUAzt#L>c8mbmjI90zOgYwCJ-18eB#(TZxbD98ttfoPm^wJ)Znl>fMzmJn` z4+4vYYulch_ayziX$hgs`m}8;aOQ$TMUc&o>1T!@dU>}uoj`XSFk4dL_w>(pKHI!2F)1<;xLwP>64~3fwe$I>+1y-*?LA+xo|J_YQkP+i z9-f87?@&&oKU!JM>;zZ8eq|!CAZrFTpKd)MjCDcQu460*UU=HCbGimiL95c+lsq0( z&_M8K8@ckEDIQp{%8Y_iuvMg^B0;lm39y-rHmDNNH*zZp2)?f;7n-l|(J1CquumLi(cV&b3Dkkl-`AJ(`LsYEpR&+Ym|bQEdG6sB!$z{SdO<=Na3R#ht6*sidGr5Z!n)S3-U#& zT*9{-1E~C|(Dw(UOyj)NG*mvVJVCAOt0*Qhi_c?wQuVbYnXJ8w`Mw#ZaujW^Z~J1G z_NP)|k2`I$DSap@eFZ|0{l90d2B6gr_l;dG3P$^_YlGsYY%^x2`dOB)_Veg$nwoM8 zbDgMu%6*S7Z3?q^NqnP!=h+yS?sM6gf{$I8z7Eh~)+WjN1%&RP8JqM#F&^puQ9uV! z__Zd)i*t7l#lL%`^RY`v$#NLhiRT$q5)U4O^TKr6Pya>RDC5hE zws?XHy1R?Vy)q21E^s`zh$uw%#~;(#2j*iJ%G%Cw74ndp{W{)xtL!W-N~~;Y&iUF| z?MBDT$5-6T{q(4)5G6%rd_R;w4)JT|$>bb|EvthL8HRCwbz)IJE52PLC5`BFkfgGa z<35U!EV2~tK}#YjYM7VV7q_^QO06<={?t<J`WyRM<(8?^p1Dt%7dxb|c$%$rVi;*E?w zoD#|KNtrKKZML;t&;IFxq*6X_65H_CEj{LFB#zrah}@D9IgGOQ_3dj-UN%kqozR?1iF+LnB7UXoHQzoM8J8Us{3)Oj5es$utUpwUn0E zB|^#5EVw(AuHn>Rkb6_@mUyINE&OmKkt~MY6@tvcj^fNo8-O?f0mgaFX`)6g%H*oC z4U(YXO5ZA65M%Arx}1@W)mwPT;wY0ClA9feDh zXtcS9Le{p2%DKD0hUQd}S*@&AU8e(TjF2|A0B7m}IL<050^AhG?xeT22595!BNM^r zy+OGaXrPuzqm)~-BF!OZkms=Hwoh)J^>R58oHQ#TWDCD4a2Fil@sZn#$=Q#RHY5G? zsdF66!Qoa}8Qc>g&O?%?8Tw+J{$rL%18#*?o4HWMbH}Y`$k$UFm!fb@z?HX7_VBMPHn2{I(>~*^ zOAN^@fXx}Vj6~bOe=r96k(_^?)tHf8MHrQ#iK5|=)r@k5L;kHZl>vuRdB_;YH0Yi? zgZ6uv3&KNvq84H{o}hv-a-;$X?~27abJ)@;19@#2BHeBkSoupMU<1w$eU1qF3S^PS zN(-o!vlMP#K2fCODmVuq_ao5NmCn_S0K!55!YYLTW6*jEkwEg{id0D_HtXhsM|u8~Z{jpoS2fiC+_D1jP(>;yo(g_$DB6PF5mAjU+|=<>R%^uA)4gHASC_J_ZITRuOg{DbNoEx zk@TnBL$=;1$cdCV%qf$BoQ(GC{Dn3)h9)B?CBaCozRor($(bd5pOg&o^*^0go(7fXI(DBXq}H&9 znj2Ky%O-KT^MS_$w`#p)WAd#-sS+}?eBkZd+k?>m0FSj%k>nfIno$HYmSkB7R%{#- z(>V0^`cpKF7cnFrbOkoImvW%8%Nt?29D(`bt=(D6BnxpQQh74U+pf%HDz*l4-j^D>sy&kh$a@IyXc0s^(^rrmiee zAhuXzftkq$Aud&qq2tr2&$q2de?Gu%ZeI^>7DkuM%PQpY++d$yPAQgC-LZkTq;h#V zDi6x1o|&nyt*&)TKor2T6%vPQbOe!%f^n0;93GvytFxC=7icm#Bw2(^zbW~clgj=z zWLw)V-!;T?GB4U*7{LzM!QIn=$7A|cXt&1>=;8xo5u95Z+11L$fg2&9m&qtp%Gkq|?e!nlxa%uSnag6uv~Wu% zUMOa`co|`mRU3eBL%|)7^QOxjg(8d0Q7lsJQ=O`N{&>w8%&Qr|+(%B{ z{=C!0;opMFfh#2{w_qkaBU5LS`NQcW~REPi}9Yrb@Ot_r~%u?1yO zz&Hee8>q?8Jo-|@4a@NW(rW@+b^Ia2|eb0Y_K^uXZfsXpHI7@ebkHb|YuWG|2y zFQESbKhmcn8#M^!wx)5ohUA>*@c#e`&bWUrNg>I7=ge}TDPVr-{W{btsmoy`Ulh3UR z_X#AvdmlN`LpxyS2RQ?$KBN3APE8D5(KK;9yC(U3)B#X}SB&%d{{V$PSg!@k$RueX zSig(R~M`R$&(QV34yrgS58 zgAy4Ejkq}{{Q7-r?2&2qmea_sX9L7bA2LQ!aUsCY;0P=RF`NUm4z+S>-bRYDX%;1U z?#xKG{{Xr%ub(PL6=NK7a6X*>0FG)YBe<5@I|eCi5=LbaN(gLZo=6=>8296vzXbNt z!5cIeFLyZ$97`zyR2~Umx^f8^>-keI;hNErZfx$Yo^~EcxkDKWPIn%^E(Qc5IeNuySOE-kK%58WsFR1(c4q4L+smE)A| zmMH|0vFVUhki*<$RF>09^TZH2RSa%oKQ2^^{p0x$uS(YUMsjVoHc>jlrHV64pWVnp zfzLpD@yH&vrwnZ@E9LS~ZXjdn{Hm(5kt~6U*cZ)rP4!1+szfDcUib5*Wx7S>oJ3i20Wf+H=F_g^W3Gnm?5HAmNnygN~ntX&QF9qG=4B zMfHr)Dxgt@*jOxU&!Obta0k6I6D%zqQ%JDB5T1I%Co=Q+<@)v079)_FFu2)kN6yanI_0PY7lQ#D5SQN6>pzERf1= zM{@G zRgBAHEJ0g_A1OaE$>ffG&MM$XnpotxM6>y~0X+1`@!^F(Z z6Bd@(#;q(T0dt(jPvOY-6w6sm3MM3yRG83$Re{er&Uifs_*AzLT3KDCy|i;j9E$C} zYl9+z{8%IIgPs$vI27v(+i$ZfrLdKm3AT=CjAch)K>&}(2Bp(dVvD||ca1JBt*4ga zQf4HqDokq_{_hw)^MmVEV^#)O8a8y>hj%0pPH;!4$2qHow;6zrIF9spiWV%f=Oco7 zz&vF7Q{si?S9w7Wt^2dEw&wgltyC1^%%w_lWNEz!iCcFKx+Wlbc<;vq5znn8b44Sn z7m-b_Os^`D8y>tKgnN&rMzgBPA(kl-f!ac$CvoY=r?2DbN{ziA%Gi+-*b1eW(`fp8 z`Wn}rgi9mIXKSgO%Sj|sue6mX__L2rxTwh_gZ{SJobAp=)!pcStu`fORe(8F8Dgi9 z#QkbU+%gb4g1I4>ZO?wy4ct{yNfO#5(nzt}CgVO-1j#tgJ7${j+oGyOE@O1uBww_X z9`8Ug+M5#@3Ydt_cmRdL=lRsqBz{)gcPwC)zR(FJnCCna2-xVqn?>8#F9;Hbf)Yivn*4iEFdtH6_t=M zVm(3X558)&%XGp!p$u-4zSjWl3O#>b0IMSA+|N7{Tiqk1YrS|_` z{HSBITL~SQK%n4|cQE7=+aUL@X-#u%YLSs-Vv1LQBSx{r+e4;Q5tD#U0LlKi^r>T! z8N#O3c}CTY4DN2E4_sAw)r3zg+%&B;i@Y%Tixc_e9^=-uOj%$q6h`J1@ zcxzQ{(uqNpHmgS-4@6=2m%e>Ts~JGkncnFq%Cf{@<(E9=iQxKVbIm?@vo2`~1H&sz zvTgoLvdYl`Dwz=D2L~A4!Stvk*d@9Qf>)V#k0%&b2Pdh){3_Xw>Igq^=ZjfbHOy!~ zcD{_?iNHSo^-mF!a^&rC%8p5<-hxe`u)D`4!wB6{HdT&7GOVmI$Q+J;{e5a^3^Hap zt|GP{Y1+PEIW5OSgOEof8R%;3+h%5!pAow**9;X)bUCNrGdOEWt?l0BB#t>^wb>%G zA;2ih!8ueRhbQqh&hJeECh0^Bo@zBKHbM zL+|fQhVoVtNBh$oIaLfs0Q4RDjQ%yG;>@2bOuuCTk|<2=ndOL(;Yd@K`-9P!sV9$0 zV#gFW6CzF>veB7ia940VgM-_>MJ)5SB2{?cUCj(Gc~SU#az3=%>DQMH$o-|5<+aH%>+Z*Gw=U}k-%bc^rKJvt8GjcLy8 zHwS&eyvJ!^Gqh}B+hvIS$d#FgC3@gmO}Mvm{Y~V{cF!gOG954Cc9Nw{lck>Qa_jAea3S z7VVlHp@Ah;y-4rqaZS0Aqe9{`SxWAOTpYLKing#7+j9{Qm`>~|+Z%Q7j-5XWsU^PY z9sIJaz^>^S^1yC5&wO)%+O835Mylwne4{Y^(Kiem%?%(56~5`(268#U&JU**deg~| zbB1+zQLq^0Li=zq3CYDoVRf}uSrEjs85m$Jg|X|@j1C7u&#yLC+C`2-H1@WUO#-vE z(l*lGgB?2Onz_R3QYFhIRh4lvy4*=|6pgu+pjB02(;mLO`_$z(1V~&>F7c47w5aRF zXhz$tjiscjAtF43apkKrf>?$;X9ci2_U}}qjbgej9P%v4xs=3qk}yYK>scg|DiDj* zig>)&@?(}T(#Yl{ZNMqUNF}=T#ykB@Q)l}!Y~L(yHsq)zft(S*;2e|B=UNw*(HF{_ zk2zE`2TU*|_C4}2dH(?G)Ye95C!RRuX>I0)Pd;gwMujO!1L}gM;l>>>=|Y6Sd8r4CgRQA&r8l$vcl3BcSR?$9jm{$8!@| zTS>hebcu3r76y?(EJo~sk_K=(^cFM2Gs0ewC4Pv59!u&EDcT`u5FZPnrzVmze;T=g(jQMg**5 zk}u+3a7fQy+&ejgmZWRRj=#5x_k-{VPJ^ z=V4>DUT?Lw$iscs9X|@)=yTMhm%=znKb z`@b?q+IEtosmD%~q}+v?dxcU$4301lf3KxN=07epY2kK}%Du2Gthwk<7{TWl&qMg< zX;>p!q%G6zxKEeOjFoAUCc$OnfO!CrdXZBX`$REGv&(rTY`bMto|)sGDX_ui&k~kE zQU%5xSPsXji+;Xy(CL*M7jZ_6(cLa6m*Xvc< zE$n7|B2OS#N|39cTzxbCHN2yAX$aXeKPj9~XA2;V85=W77ah(R^*9Fr9=HRoCzKK! zo27nB9gBgus5k`r9x?cOR+GVP3p@`jyW~~IA}o37)1c3Ptuk+wyol}4B#Nrfjo2gd ztX!Hya^@hN4xwiZaY?zOJAAf6t~>SULC-* zscMX4*dL%OUpX1csQ$>2IUsL9@q-chgA5##`2PS}!OB|dVNy3`A#F9h5k+jxAZE@3 z5V;@WlT&`~&k-2W*|&Y8%0L4*Zrt(4eX7>Sj&0WA_B21cNdW>iKF90&)p&`Xe=1oL z8)cbsa_SXVzc>f$ftt8V{YjGLAbmpOMG`75#g%uB-dI&VNj#ngdV5k`UR}XDJ>9a! zaUf<`)&Leb*pi2nmK$--dCq!NliJ)ki^@e zZpe!ivu(NFvN&ffRSyG?LVbO`Du@oU%w9!rA~_mqFnWXk0N3k8lx?A`d19G6%4L>M zyS0}Qw(!AE(yS%T)Hr{$t4jb~tk`8Bcg8vTR%|<(QegpNibYmtJ9D2w`1Pw(G_k-! z$Rt)fT4LXK86;OMl0)Z@aTekU7^|ZQVb7FTh5+>*!1`6FqMlbjCz*(jQW!^<1S|4} zY?SuT*oAM-Mt1?3wGpn{A)g|MIcVZYw&ywAz?}a8DxPgZG_{|}StUv5Rk!;@MIF269QMx~)qJc^9k~I#!6O6* zXjD9Zocq+0PqxK`Bh2$*Smk-6QUJ(2WMx=msKLfZLP5$>=3;hZ);SDV5g9(vNt??d zw)!8ZL7K699C1bEMYPSB+bM&dha8T*LH#{y2&G&ILlR)5X$Jf@TN!jL9RzkS@$NRYJ`HFmUtdh!s&zZb=p_6Vv@9r>q z)TYqftY<=^-Qxs#OB%?kca|!x&Rm{@r~r1URzW?qkThaBWr(a`94wj7KDi#%b)$+~ zxklBNCX_1>fN|KL)AJP>4z~~H%5Cl9jj&a+ttTLH-yXj8q#RxDG~*(Tp%(ao$_7Z| z9Z3pt^D6K%GJ4~+QIgN>t#XQ}v7-iv;0&Df8T=~Tr)%U4<{(y4g&ToCj(G3uR>YQG zL}kMfJk0NLBt=f#@L72xw3q0NG+}5mN?yv?%}-X@=kHUABp7qRPjl;i)nsY zV7J{QV1lYo>(`EPP~A1Rn>3JHPLaoR^T=fqD@b`edJ?(G9AI?M6)aZvm(nxH%qQBc zvyj2E4sq+~PJQc<>O`W6=ChV4UPh6DirJVam4=Z>BxgA5{cDXdU0les%#lYNQV%7~ z!7kDI6~Nohd!B>nJD8_gR^=o-!*1B*{`0W_^!5J$BCx*0c^i2~%Hd+TMcr=cwU#nB z0s-Z6FhL!N^`vh~ud-(;aE@*sSlGt0M$Uk#D$D&2YSQWL14k-8WR;hG@J0i5$r(K= z)x*f98)&WOXL16_2r9!IC>=q_-$8? zjc;#rbBjw=hTO`Kh^_J?UzgvY?T&i;Q70qrGW;l3pgv zo>XUtmR4>LVYr?-&IMbB(ng62<|lV5=*^YdeQThK4=yQTSk)F-wzNse9+>a#O(;cf zOz{(u#_K*DYvCo#F5y|w0vl<^e0v)4j~DnBMoYI+Rc6jpZWWkyA6|3KeI4X0MQZNT zF|#8Op=iTC2=)vxcpWqE(x#`S&3h{kDm$U&?wO;6tZKa%Bm2XEPjklsE;`cP?8B9@znEO&WZatX!=dO3?qT%vs77C zu)Ei;KyFDG!6S}6`TK&`!`5-^HzA`(5@qdBF;kC|jDi7f3G4|tbCs=RM|YZQ|a z8?5e(8I&FiF~>sOW8a>&^VrOz1B!R49%Jo4*DT}MDk@foZina3jJ!L2V}2}bfQ|qM zoQW80C_TTPfBN-@f8l97G^+AX73bQ~wiJPtmx6Y&ZVBfcb;0YJ`XVhUu6$p6Z8>RU zwnALWyRn`?=e9;a`r@JS-i>Dsg`s#(%Xo~}o8sEhkPZh?$3jWR)4hCNKOw z={(X(6yVmcsq&0IAG^ELF0QTsm14V#7IVS4Zr!<9q5Hskj-IsrM$lbe+uCRa;<{@eC2+b-7Dh9? zUP6LJOMl)hWl!-O{G&MJ`uo?y=6O^wuzf#Mc}+^A)V<+*aiu}#YXT{+ASY~cFeXFw z{4vFJFQmhHc05Ti@*o#X>!MlQvPP;-O8nW#!NA?P@y|Flli{r<-tP9w zlm-okOpr!K0m$p^(z~mh3yJ2MXar5AL3mmM2>s%q+(vo>pU0=Ie8jL)aejtsNE}u@4#?6*!u9Ol2lfsZl_s_YnBGt9+Y6#)9SD8}V5yl4uih_a>a>a9#2#hzvk=il(4Qdz2MROS@u(~{OXCH{+7jT!a7d2z zoHSluF|cFqoaZ^~xK{;zH`#aHz;CXuu6OyC_ZFLDg^Bx-zJ6dv7~~8RM?fn5wuj}d zobj?vbeNK142)PSf%3LgatZeyhP>(GDqaITr_RGoW;}T9gcl{KDG63m*AWG#7L6D=sm^a zZnlSLEeYz|zlS}Cq4vdkUB|)pw6`Ntg{=6&j!SYI1Of^D4;9;&aOPo+sd{i{&gR*U z6At-g)z6uJ416@bGaW+e(apGvZM+vQ8J1wja|{AD{o(=SZW-y%=-+|#Z?oyC9$Gn3 z)j--dx2<{ahO}F2YY5WO78bQ}`^}>*fCdj^oLAF62-6ljSR@GUWgDb!LY};1u^-`I ztnj}MeNnDuc7A`4t2*@*qp{Ozx+A11BBt`Opg|%A1cC@S{_s5U?de{lq*^pkwY;Oq zoq=H^v2IEFXQqEjew}PS!qZ5SA%^6KT#c&+FsIw*>V5lGtD?HcZRW<;CG#ObNnDKe z$0~h(yjSWNY#b;ae4X#1%IZj$_mZWwQa!43pPHlt911z;00M!>7{@$U zp$MeTd$0tN(2jZ4fKzgD&loi7Xe5G46~QoU#)}mSg9F9XM##Hq+1OXYISji~g-^uIO z9P!$wn+!4Y2Hl1EPxqMOW}hS3PIX%!yW0>mu)AR zGO;blQjBrmqg&@Xv4E|>n(8uQ|oxLzB-AfWjGqQ}RQUT|8 zYN*Vt#X@Hzb8ZfUfz9$VrON2-^L3DUvE#wwHT-cn1u>H zW+$MoRlLaAT?>gB(8}4`s(}2&o_le?&2*_R%B=Z8o)_+tG2vMezN8FK|v18O@ z-0_N!%Q3u-!$|wESQCIvX5Q*e7--=U$o^qjB$0`dGr$2r7$EXVJup3Z=1xPk-h#nv zJ6Wuc8)0Q#!#j63`OR3CE5t6vRIJ;Ivk{zU`ihFrQA?Obv&p&q!HDC*!xN9w-n%I* z>`d1AhB?*yYc@3 z3WrHHW6dI>N*$w8LW3!3BJM|Sez^YtCYEPWEU|7_+C1eEvH|+{9)x;UWY@NkHN-m$ z%*?o$Kioc;@0|YtD#>j@nqRZb>kwVbDQx`N&!;t;v`}(Rq0|?;@}dw&6st5llgpSh zw0Y-u_gf(0P7W}78hjdk{I1?&vc)Mu{*4W^?$c##>WGU!#(z?bb6p>1+IaUfEIOK8f!REO+m(C5(CCh7!&(SLMd zMOdT&H_Cc}pYzWZ*IhgSu$gf)DcJG0R0`%UUIm&ZX9|j?nVgPTRt}rFylQAzMOf}< zlg-|)p+e^YRDOWwopQ6wa{@+VfX5n{OJwXDA$J!HS$mHB9-Mpn)8=Uktv*z2y|gO-0Bvb-VcR4NCRfaVOlO<}oE|?K z5wt>$@HyDtM4&n4$ByWEf)R($sA|t>*-wCKWLtKE)(~1 z!~sFe5;-4-0+GRcOvjqY$2p8hSTM+T1%O=isI;Qi_l1dRU8O47KvqAesKbatJsBwI-(9;ZKt$LdO`-EXTOV z01o7OR5tfk_VG-QH1f2vZF0;@GWN%(;r%N&z{sZRSaPPMbk^?yohFuR?L{sAXs+H<3qE>=10y)>Ml)3* zkP@U59MVe68wYmYqO+P?pgh}oE_C}cPg=&axE9hcoh!5r7}{ea0r8%vj{gA8ql)54o@R`h1HQ>om=dI~AQ9D0di&KW zXg0Y{wma)wEBUby>Z`CY=smxm(y(=fi^^XlWFcicSdfdJK>W{2pqtVul^Qs}8(kSU zHs52_PJ54kTDKAZ07fQKxj`dkQvyMrILYJzjQ8t~aa9u;CgriiT-!$y%ZTw5sujG< zHt+ucT|NVDmiJynF~=k0_fQf5=NKQ)HKj3zTozE+eh@MFeF^qGKDA!f1xC3s1lfSF zObZDkBRL*~9Q}Cf)}8b=f{#)du4ghm$|}2}W6OSakPv7u0Qxw(#4VsWkHxw>VjF zgUn(M12FmzuT0ddn^b(XjSR9fgg+|fyY$Z<+;V-X^4=J4Ch}6w=Fu%w++8H@WD;ZL zjZlC%B;}7n1~Lw58tys9=1BsqXt6>g46-&3Z%P+akj? zyD-2|$>qA?vT>d`{eK!aGyec)c|uv%-XRfrB#`ZlD)Y%W9S?e0w+Tm^3&9IT`>8y! zmGsCzhI3kRDmjZYGf2v~G5}j}?}9PSYZ$)8$K8&^A8WTT?txNNx<+UuiGfhugUCH| z+v)36rh2((5DziN~>mKcuUazN{W&0Ly6A(rA;l^sfev4Fd|>w(bm{&P@;z1}WJ z#gu{9WY7jykN{2z=)e)vvwPA|Qe%~zSk|~$VzMx(4RWBC7|7?pe%%kRy;`}&JgJqo^H^m;$surl zVc!+cC_ZhCVa+5#0koP{m9Ak~OW}hdRbkkX$>Z9rvQKiZW@U{fiGJwE&AYeZ{VF&i z)8Z0N2bVLh*O^ER5cLDo{{XK_5!yoRvB+(|)x$Ej8ytdgLFh+JR+lu?rje@6aH}{- za4-i@eLD1|is+-ci}#4~w&>(wp^v}kQnT)o=gU~3lH=wd#SD4psmUO8=k=ttvWjT2 zHlCB0-S&no3~boI?g=BPKTavT7}}b-ZfG70h}cJO9ICsaiV&{|^iHH2ffh*`X{T`v ztohDzCeA(Q2EjyUXd-~1}_s>H4?AOc8$xgoOOr;g}K#^%&zmw2>{?JwLdSI>jaj6U7>hEiWaWo$c*ng&%POg!R+b?0MygphoxM2&k?&ehs9#^h z6zvt7tXC?pa`(k%oRY+nxFP<&6xrI?*d~r`0WoD4EVU9TTIj0RrDw9J54=i(B zqeUQ<70AOYHsDAE938_LKI7?C(rGuwAO<`~ZPA}5YTBrZthdv`qhR<>3LUh85RZ#>0?Fgv>RI0uhvaWOVo z)cv9mzFVstf&K^j3Y7#z(st0a9$Q3-h}?}A$+7awo(SWiCp;RB9t+vmdJBIpCGy!A zN66rlfzKYj`Rh`&t0Kn?vlWVIBl9hmLaQW;oxE}~0X+7}_pG^=L?zNTR@};foPsmO z7K%D;W?gc8$fIKM%Wo-YNy@7ZnLWQh=~r4Wv&1DVijIX^W?jk~B%B`n5Pu$+tm7?t(;6M5U9-g-U}q ze|Xu+1JLuHeLo7P=1B3EWoU$QuG|5&lpLOU>->+kYyFwQ7WWWM9JdP365XpQ2y=!# zcxAyJxgNDmMCkFx_U@q_T_ckmuVakz5A_r|q+pZQ@V!-l?>5_&CbvWPzL!&N&?i z^{TeYti{_gNwagYVn;k;s?T=UQ^cE*phr;=ivXzyocfM2fzal(-5SEHY`qIK@tc|F zIWjIwjz{_8ufr( zKAEg0X12YZqG_5-ks72W%LZY_6m-ud{v4hKM7d3D+BB|=vD^)Xn`~omUzvZ&sJBZT zGTzG^scfN<8dU*gkxowDqaYA_ao4q6w-HDOpLCFiRDcKAaUhLN`_6zn8xg!_v?%d{xw_45?jR4!G>8Gm`H(J zJvk#e;ACglrA_B?XWVIDkTAxn;?(yr%@<`VHAhO z7$eKM5P%af2;49Pbk76aW9d`d6?AVl;bV|151oH^7$lzAIOqA*7=lZ-8_adCAowbCu-4)H$pJ@H)GEE|odXa+LNCmOjXRRW6(n%cm5xin_+*0B&vTY|k zb>xpqb6ZJn?QbHdnj~GIDK4kbbB;+Jy9$O6Iph!zGU$Z;+>%BWvyP+;4EMmOyiu$s z+e773JCh6~y1KQvjFFNCJ9Y0=zSnTG!8~saDKWv4c*CnP=m0n&v(9ScBO>B7pL}bX zm^RQ*@KkZf{{UW}XMF9t)+B=6B`0^CZnA9ykQa7#l7EPEjQZA*Z9AJ^T}a+Jc0}^I zkhwp+a0@eFWc&_)&MPiyjCU}sh0rs%lP1E+xOExn-=Y4M zqOQ?5nJ88yGQ?nTzIT=cYCnJIhCyX4`xtdFXG~?v+HwBN+C3g{w+kPVMyrz^w-KZAT&YPylDkSqTx}mpkW7&7g<;R0#CeXRJ9D1-+DhRN zu|Ts45J}}MXob|1w6A}m&-1LDWQ&9@RB0qsk1;H2K50UHs(!U-85L(MZ41K)R*}I_ zOCM2?#~8<;{A#&U^1O0Bm5^hZ460FSH0u?HOL2V?_IfU zXZqGIGCAbaA(j|qx0XS5_GdFHnG3m9EI`XDf=Z0_1CGA+YS~^UNRnpr4r7JZP^FoH z&mBlBoc^_36*9*)yUd8N{J;V-#9)l~1RkE|plC{&C-bFGG_r@8iHtX-HsMiRj1QwNJfrvNPOyl1M_4Zdy4A`^BF>DI8!P zxjvM!#1=^-X4>e-a9l88Jr6<&ecY!G2{>=?sbv#GA(;XQ=C&xs zq1_=|^i$a99XoN}n9(!Hq!!sL4a%G_T=vfc(y6=MK`!}Su2wR@+uJCOnMvSsNX{@b z)7W&Z~YOl2)iVCM&@6-0usmDr}L;~vx(q%gpx$A+vC|7W0BAtk$`$<-l9>IQA+I-1dc^1 zI?0gRnnNH8cpwdMIb|v zK>59R2ZQQ8D^?p*3p%{Og(Xp23{QHLlVeKeLrV+XLy1aEP;vHGXxT?myBJfP5uUvI zRf*cxNg87mR{l-9;gFs|JoO~@2h)K{gqE3+f+v{UN}OY{9D4dyDT+xW`GuozBsZ4v z0IC5aIR}tH&*xgfXiVXBShV@nMS{71nDixa$MVHnvnVc{GN@>gzt)_n9QvMWgpwhF zZcyxL;1B!7+5!%ocIVcFxez?!NOvqzM$yg>%Of{c0P~UGJaRBiRHDq(BwAa5E?F(E zO_R-TN82G#B=Xqd*CZ3Qfgq0Hkx#mf9u`5iR)hwR7|Uby$u&xNL&lRr8z_Zhh>$Qd zoDau8odM%4e8jj(6tdi8kfC<=>BqRwTy`~+PpPzFuEJj4v{T!xW^pW#vX7LNVbFrz zk3Bo{O1s?2Iu9_$gZ&&Innvk`=rVJWoDX`fdp2f*D4>#PRS5mk5X#=Ax^vid>r*nr z1*1Leq9~e8yXBK<$mg#fnc}mYQ)RsoV%S`*+FOf@cq5-4T(>rdY<}(rNgc=>{&f`i zGJz3hXycR1xHw>^JP)R6hT>Tod$gK6sL>Z>VT!Xc?3n}Hl6d#47!pSWi5W9S11tzJ zmd8)mp`}X9=cy?bW`ImpWFcGS{oZ}KW0BK5QiyI#q*ku5ZH=(S!iHQNf=&k`BOU($ z8j$a6pPmmpbU!8`EMsr*&w3G>crPTDHiZy;!NACmIL~l0d;8+LQIctmnWPqmIAoSE z7;k%g7AkmU&%aNhKD87Up&H|K;K4Hdk@5^=bHP0O=dZn3xj=;xWI()Ox@3R)=>@d+ zlclr~#1-WwrIv84FdHF3AU1tE3Az7J6BmM3(j=$GMqPZ|kvE`;n z)!nc%!ys-yUYV@yky1$z*_&vlic7sJ{{G70Rqi6PzFT=1e-f;RJ5RZ!zqyJDR^Hi6 zD|F13qG<~=4oC$501*IkaoC!cd0H7`fD~ge`Q3TizW#*z8YV<&Zf0P6nV?_&Z@~bXR;$QeqNWjN(eT}cMqD$rrhF`Qx z_vDe8V*|PC`g2un;(^u~Oqh*GR0JIL?fBJ+oLadvCDp8AJ;g2@7Jfz>1A?qM9q>hK zOO#TRlPJKms?X%4a=T8a%_8@Ffww4Bz)-4ibNB)(cKbBSrWBGFg;_<-yp1QFyCjmQqYUl9z`!2$U&~nDM7M~x z(sl{*;1Wq}dt{T3dYs){e1t=9L?{#n9A^Up zpntYIwaJbl3>$VjN?5XV$r#6fe$`fOL7L_mY|_q2BUV|YmdM<2dHN~N0X~D?xtuJ> zS9dR=jY(+{UKrwS@sfUKJ@dif^u<_`D>*}~1#*R4#nrca8q0!7M6C_m!ro>G+Zj+7 zIO)$pS~l*mNg*o8V=Ba{84>3I{SU9wg=E6ZxXXwVTV&c4MC!^|0sgQaN7Pk)mQi_d zp=nrd!x+NI$G7WOF%+ujWKtuR+K$97=KdjqK45tsDk}Mw(?(WF6pW38@IhP4DSyY4>o&2bDS}+9Yk;@)!u@Ju!ox zG7frv6|&`BNT|KyMkmdkMi+Qk%%OII6d${Q27O4Xiq|k1+I4xQj7R0cB7nv=KYKj( zub?tdckdBFTSRdH)@v&TD5s3KNe!bmbH;OE$bf<5U|=1jLc68`|l z!^&dwqJ~L}eVnOP+m11wc=aZwoJffg-3by9ReaFQ21q#ok~^M#s*H}7-fG18n&C&5 zPIDTb4?ok?3VRft_dlEO+lQ@MRcf_VC=z?rs*1gn*n5W#+ z2eFE3ZEcXEXk&fo_&$05fxPZlez>puI?wm}IOcd8n(-YIFC8us5J@F!z%R@@KZ7}4 z_mi^2qLK9xCMtW{h0hOYZSf{_Prn|HF=DJf8~ffTy6hQ1cL+SMxvo9)?@yh+o?va) zUlWJgdG!BP&(pbWwvvyXW2F@w38G701XC|A_e${;|0d{4sV({L^Y-c8`_U)0M9iW1 zp}F%{*1~CH%ujsi-BW>{OpNV&I!oL`+RD9&#tS3k-KN(r*c=8PCJ0#R)*4Ora)shQ zz4-{w^FSjO>^5iUWK8kY~um zTSFlVwW%W12`b6!{~vdiN(w5_AsW5FvQa_FLC^X?fx8wEsqym{H{3H(z|81~`-vxy z8$>e}QIDBrCC!Yc`)NYjkf@!80ui*#+_ajW&PCN-`5=*r9LO%#qOxbMyivoon-K1A&~Yn>Bw6CWx7S z^Qh#2E({j_D(e}!-%0Bb38M*n`lg$>*jo3{#*#+X(V?NM2Wp+R3YhS81@mu*sU}1- z%a3V(9B#)y9KB25vTZct^Q0=F(tDO(B==97u_MIM=+%SQfjtN?=<1>cp16d7FD_kw zg29b_BlML8tExI#^%Ha4vy~`@D$o9$UVUn;bARJbLUIR`c}dSwWim${p`X9+dTf6$ z5=}qVB;SfGTy4JJA`=|fe|-v-=FYsR^f%DldN{MN*2oerl0po|{KaBur>y&ykgElMp0a2;YMDQ|BG z?!U>gHoPmXn_=}#)Czfm{F2cxnfvsy{uUWM#y^k@+$FZw;jU)f{{e5S$3Sj1VM}6> zLqNG9&X%>8YuUwHTpmGRX?|M$nz2n5{$?weIgWqz!kLTZ_%BQRaKqPTjE;P&TU_HDt{nKk}4u`uX27i9zSh&!}~%o5-$H@gJ=}@EQB1JFC#D zm-%57|5!v>{jMMbpSW zaf0h|&PS}8z48Ft6Ik_rpBEQ#S22}ar;*P$K*-_IW5!=SvTAwK3ttPq*$CyQYK_wa zO3lAKmznbc)w>l7QGprfevkC4Z*J^+_&8_ThHtY>_nYjBsOFNRB%f8Ysc+#Sw^5c9dJ{kG`yh2(3Q~2nkZ|8q0LBFLP~rB^=4ML(5J4@G$DDJ%uD^ zHM#(v_!;{?Zr?%Mqg|iGb>yLoU=S2HbeaPOdRmy6m}pL_x^>^+3w6GmwIsZ;$P?El zhpq=DqaXk`40w)HXsb99qrEaCRuK2L!jXQJOdNZM>A8kaoHdBotA^Sc)0N)n$1?An zJtt#ZuNS|IjzuUGY^qoxk9ISMk(p3hH}m~jW%zRa{mw~wR~YYYiP2nCJ(inrZE&DU~d$Ru)dy{U(bB9vht;hA9=bq{3v@UgD-tJx=O zraGt3C@`9bS5|^w@Cq+FtETPW`vmv$&PH!rq8K<{Cf_mN?Qd%0pe6cHtNxmOo}c;Y zP13U7S|po~gJ}u@VVmF4ENYWO5D7E|5fZ>^4KfuUA8#GWIZaJ9ynUkIj>Y5jDEQ=_ zcUgR!{kBI^T2T5B{$F38eRdJovlRqO%XSP?SY!LjnpOnpv;6wQQD5qH)6nS-QKFJ6 zHF^gz;Q5x9;89QgM889Ug@H}d#XXAEiolDAqT5=oMl5W!2TCum@~2HD#f|nS=5{6~ zZy`1ZtnQK=Roh41ZgI4wa|Z}Ae=JuC9fgxgOiyD!s*W!jc6X=G6(#=p03HnC0$u;Y zL>`ix64g79=~mHE+h-HpBTN`Iiu1aF?Wjv* z2Ku2#VuJw-%*Av`ECwCc$%Qf%M_G2SGNCt_VStbc0;jY@ueekgx3aw+dmTbPvOW9Z zM{fIB2MoCyjjIYGeIHB}#8ugvq=pVc>32eK(VHa!HGcF@@+-Z(h1ek=D~ z82lb(d;D;5nzsz96z>10%q#P6h=YO6fscD}^tP$g(lMK;>YH-Baz4c~ey^Np;<{I} ztyrJw7EIarO#>6n_+ZR6LW%P=#}W7D&s-2Rd{W@Pv?*AlaM#u|%EdDut+1etCnan@ z3QX;J9e@lUL#_S?3;yVslHp~8b>wX#XvBKm8ro((JcOyWcf(*$7EHSgm4vL*_!9>; z%+2+rrgQYa|8r#3yF>%H)zZ40e5l9n8O;8M%#o6~_^u9a@e7cSUeJq7TbQ!uOyZ^* zVlHT|!^S+C6hlphzdl$26+d2Id-||@MNZB>K_zwTD*>x&gT~rmd5$*H1ubqC%|`O{ zU6YYPH_iu*)mJJR_C`UQM9{=25gr| z_>AONV30I-i7tH)Yx{bO32ihwoSYM|l391`aMZcbmpi@{d^@Whhv0rksll3S2^?!OMh%tA5XmV48 z@kcL=w`r1$WqxbnZ(vWk!_m%s^fd5!B68we4O4Cq(gneBm(MxX_LMVZ@e83QW+{SF zTEz43SH{Cr@zl%*p;6mj^L$-?1?D6M0~HqUe6I~Z)^x5agpog`%M!6xz4U9zhnE{K zA`FYH+V#2qexcqy8{EjA?Z7*(3yn1y3M6{6yu7^40bnk5s{Op#C4x;g^g*w!PYQK^ z6#Dd*stt!cmAm8?2xYP1ECs%r-wWA`$rtHeeV|CS>m*kPU7eO+?2bM?G3jyWf4R*N z#c0xa8o)Hwo{J9SJtZp+ltegST zxXrABT-3-X-zZY;DPftuz;TWhaOi9~nOMl`L$E{*n~HGK6$a&Vh&+v(cc*GFT5e;?qLZc@lG|bW7JR1 z8Wl|fHvOED}VroRABFEw5 z3_B4Gd-gCC%iE5F8=S}s^pzJH{w4GN)LWDBk5yaRkr`Fvq7f5hM(wciuqxU;d!a#T zYfsJyaq`UVG?|vM5>3RahWzz2c)%~(o2Q?GJ9z;KmRd~SI<(roDQO%)qc~QPJ^ctW z&Bng}cbGW_j$5vuf&~U}WHfUlv}Aiq_Pz-0I z{V=YZJjmGvbrPD0d81;D3@)$UthUR>KxIexDn(E#uBF7mrmV==6tiKUjR`7s6Vn>` zwJtvc6LaN#(xk6thRC}1%h8-h?vE4Bwjbku@3m?Hb|#h5E1?&CCz;8+7@`^r@bq#o zuapd;=zcpEUMl1F>Y2;E?nnxZ2`!}vfS3^~HG1*=PhD18QSa*AKYBjmzUCag(plNU zt|*fhjfKQX_u0kI_p{^2+lh}{%&L(3O*}{D!cKBHw3svf5J9AleEQDG#f`7c2`*K_ z#03)=F-oc>&o1V1FW7L;-W&8Oh{lI+X!;ZO=#n6O`D3D_e#QV2Q>SSc=&sJ}^q6jz zxPrSh3)dj9*;}grt+C|rX5`=srCoN(`!e))GEVEuUO8s}TciuhQpU>Wl<7#AVUqt2 zco6hEI>b<{B+6<;eEik4O6X8pXxz}z6NUY^#UBH0{aY5-T1)SZ0L3MuW`A*-3#f6F zz8hzb3std>0%nMLBykHx(vO-7td2(KDBt%bFH-PKv-SmdJSD%&Oe=dt-!E@y2DRn) z7y4Drs@5|#?s1*sW$uUd{fx`jaS;AEUtd?TRS2qkY{mG~MZ1dXp>riQzZ)oV@))KD zt4f7^gBe*Gq(59rg1N<2=>HQvMFcA^y`6;?z3w@h67!xPeGHRPmEOKa~Z)@>Tr6-Y$n1MSL#q&5u2 zyWFC=Gd}k`c z)+;urmnQu}L5g;^uJz&+YJWqriN=fNVV*I)M6VL(DHO6xU+ITDW?+XD*WgeW&JF6# zGGCHw9RCLW8256L!27(*IBPY#8_v$!_NJ<#ZkAc8X%#wbu<#(gX!4HWO^LZ;igAwc zLG{uFOhr^>FIITf=xyIzKNCnK5evdxsh7Dm8~jfAeb1mrnyWW^5A38FNKfqke-p&l zw)~bBT`^9yMWd=y1O7A0)M@Z^p*=U$W6{>K9^EPfMqazp0Y`mb#)boJMZ=I=jC7NqYv ztmWHFRTMIC=Y%5gv)?FPh6o{hef+PX-x2?ulem6(#H($u$Q?`fTQ&UsW_R{K3YKcC zrw_l3gtp9Zq~y|(?@KgcfBxmyf^0u{CQJq~PD?*hKtZ|CM7khVzFy$sGJ4@ELdyf| z6X=ni`rQtij6aY^dx;#x{W7j8uI+|qPz%5oAaWbplm**tOc_yY6JOJ`Apk(Iua~Fy zcG5Rlg#{=F@}n7MBMP?{CvO#05@El52ca1MV20b}tYd(J9fKjr+jIB}Z1pWODkOr+>oOb=+~Df=@Pr_2XWi7>I;`7^M1! z+a{iea0Seq^FnI(mz%VU5#O6$@np3!QFgGHBjQY=KeA@rX8UHm;P6&F{q7D0Q3QOn zzxA`i+UIQ;=o)2O!>u=Pa%+c4z9UM|QgB?KOfDS80ZQM`C<9%)VTsq)H=YgXv#|>;CyNx_GNF!I0pjXou$C&_)i4?1Uk3hhwqImZ#K);CGQBMt9>^`6Kh?h4s%AtIG(q3_*|RaBZ}sXN>8fxPj`yY)&J3Ry}u zvV7~f5QSHqTuAh zv@{wX04=d`Et{>8;YgZFRyv!DmVi~eES41P_Pg<@F3d4efRdeyq3aZ6y|Q%>M)7nv z%UVkXC65+1)k47lh~B1sX^e$Y0cm`?7GIo5?+C}W$SFsEYVMYIP(2-8G}*O%mWUNk zTw+cJoo;3O?nzfa_wB{h{Ijws~>HI!1*G$2X zw@>VaBZnEI!3n^(=zuXNm~xJ;m0&RvBPOF7@6nAA-hgu~9|}%#(Uqw(hfL0KpSN_0 z`v5`>bXtTviap*H`ri@cpMJzvUda77sv#u@`x>m_74o~l8YFv!s|lGaZ@%AcfR!}U zrmNFE0tKks_%S#azoG`8p%V6oshwf&a;jKZ@d1?=l%K;Noh_I^%M z!IuXveeyaSJojIGiUa9r5Su)ERV;^MNAd7pGd8e4V7kQ-|3M_|t1B1ZDB?vp0h9O3 z^T9pQCh7H;87J5*B}oQqMDGs`R@)hN&jp9S4ou3k4Bs}Ejjag z4*v1X64nv6^`5)9Kzl*1qeg4w8Clj49kyKplNx?YZ`E4ROZCu6K9hQ4=iftsN6Ax3 zt}^b`AMkG3xusubm8Ls!S)ga6^y$O|PXIZe0K8h3+->FfvXhn253Nbp5^Fz#!sjjo^KoGguDOdF$`+9JGELSdz`yxLFcS;Kfc-~CRfJJm7*$CzA(}X zmOLMLh*0+8jog{f65ag%O!1O!=%S$OU6M>wyV282I1G&rg|0IGq~KMap9${J*QT+n z^59SIeBfC6ugm0{l7H3vHEHhf$$NpGJA?#{xp$z`fe4;$o(03O&FQqopTrttuQ`by zVJ3GGV^yedhi#7uOQ$tt+0?HCY23V9$Js= zi2b9#zC%>83T$bLF4kU1O_YaPBsC*^mJUExz5m9$q0GWPtb5+<^kh0-gi8oN)s-@;7uY3M|NN<3CoXkN!|5Z(n%DvgpaO(0s z-suz+f!ODuo>Wm}#;c1jJ(CNxov-6(vY!qB_-0PLh7L|DUEr?vtwu8iM5m6cv5IsX zPam&GeX7iA@yy`gPdVkv8g%0iBTK9uQK>&VGgt*Sc00mV>(7R`6ha&C6f@nCHwGB> zvlP+g0?-9cf5E)7YJX47f7l74XwoL39{zev5Z}7*6h!KS`0>^Th#!xktl6*D<2m3i zul`OL%-!jW4 zQF5ujPc6%G65F;$I_Y|>(;%8yh#RmHyi=8#&lRwJ=6$I z;s^V0Loo^M`RPyWPE$9MuQKnA2juPdRG@D3qvC~Ft&YBQ#8$tX`)WH=^^K}!;-pJ`qci~M%GgnRPJZEPD zulyvjq^Or+)>djHEd1?3I;yEgbT}oc!T-xS(n=BQYI5_F*@@Dx?$bwFJj$ znH$1I?Faf{HJQSDE@(G3GA%qeJ2u0|;^Ppt2R>U)DLiQ?@1Olyb9p^Xq;4^^F*fw` zYkMqA=m>Azd)>~xO$Em-wusxi_q_2ac_c>T9Hm!8wZ81_Q0$e*9lPtJKQ7KOF1yGZ zQrh~o`lis7KsqO0rK7J~J7s_WbF;0W_xk`t^O^rq+-HMPm15ho9+*%~946_XoQUGc zbj9We#UR5FNtAfi({TR+q2BK?Ni2`U24wY*{K@vw;ymSi&!De_GIAY*yu>Nm#`2G& zG}AjL3gsC%?tcR%kk!v8n}rfaBO9VOQdMk9xLogAOsKBxSWMf}VBWpWUZ^sB=2tOx zDj$nOX;RnT&r*gG+#?76GkV1~VFYH>H<2Y5U0;afM3Ggwk&I0*$9m=f@T+BCHs{^) zfa5#A1buXK#&72v*T^Og7ieu!gZN_3XFMIIoZ=SV3+BjGzh!ydN^|{e``)J<-CUI! z`Tl91n3+>{OjYTxrd^n`JhW{$;z;uO&!F1sz)nxO*F7np@qO$EX7uii^*3hP?U}B? z&^NF-d~y=4OcaCU+*X7$#7G(HF|6)p8_O z0swrG)ySup70^A&rg4bPMh_CVduT(@TiG)@IB0KSm>9Y|KeUB6$iX-YXrMbi`A^K< z9{@D@ApR`B8U=4g6^QwN`>nE}Tr2eT;@>4uOq&%nuuz`H4@ zkZaWCJ9~|5Bi;XrPkT)SNqu_nIjiSh9`5MHAvkyEN~*coey5ZMAOi{`)<9~zoa~P* zC0qXaPSuO}i_Y;C9pRdFd?@Z_?*fmrA{_mPR-*yGy{OgCeZ7h7c>iv>BY`J1;nvx7 zi|-+hgr4RyOeH+s&QVKzUH^%zyh_)AmPt6V?2o)5gG30`;1H8cGQamys@pvJ^eD0j0T%CsK`&yEL?!6gbjdCWMZ@bQu zRp884a@b$uZ>lcAz}APAMWcc0)Bo&(n?c#=`iqnQmJ$r~j>{EdcB38{{~p?tmlc`j zN9RO)ty?9z06xC!*RJ{YK#JEfsVq|llz7G;ZS%^)GM%FWI*bn;z1sA2=Px+bctJd` z`xx_^O zaAuy+VJia=OXp4-GOb@ML3m0Ag59e!qNHGkUbC;Fk?GP;+;4FXcvs7#+s>{p_nKi| zH>>=(^TtVc5f=2$ReWXWWQ@jND}5ii+`V?|ue~T3h*eBjYMN%3(*isd?T&GJtWN}?qLUyd8jt6Zf_?G^ znZZ%3KdA2lkdxFUEu6yntXK)nEm2Wj{|_f_=oqgL)jEp%A_xiZ7S${J`1!&01sGb? zDN3Xp+C)?dlMmH;W-XHS_+XhNktQWL%BP4hkzv;7+D0OAoGwyRdVJijX7<=4klPlx zUZ}g7`Z0mdBz497mLKty>Mm_(JqiK}zyf$g=Lr%X@Q6|_{Pm}W< zODo@IP5Rc(J8x^=H$cEfl#r-^d?F9vN+fAF7OK@Uw_dA2&OHUQVJQP@bB3P~ks*pUq`{1n87aZ;s2d>(ENW4I4u0_5 zz|*^v%(AA;;d~Tdwbb64LxKaUd)VoV?`$7G8IhEMC&3ZXVYNe?1Iumts%P))|Jgng zaDiTLL$C*M4E&0;RF{XnS36}4e-D!qK>p%LENbI#bB>Pj!f1?_27$2VG6i}_O79&Q zP{2A$HSGNGpThp?sxX4}QEofE=9Y{kt$eAemKj8NNv>%D*YR}oO8VxVNiN{;=K0_E zg0Z1HsKl^<%1F1H3K|9{fc;P!GAy2K97CK|@f~?Tj$$q?ljJuc;tx zKXe4ac@w(59yV%PN;@(4cJm3s4|$DYgseay0_s*=VNvUr_GI+8J8S6(so{~}Q*!4d zOxMfqw=7x9ONt4*Ke6-z&(JfF^>otvquYx&Gk}EH>1e8|GwRwyTa!*gOxNg#YgrOc1DPXHHN=;!WL&K*AQC&zESif!1awlN6ipt16 zSj7z!3U?6i^CvsFx!ikuif-3XOJ?yn2U-5%E2g=e;~4LY`Zvd*3mfZrm9mDGHr2U; z|9dF4j>0QXdWhtYdbd+gntwj!{vQS3xmoixd`r|S+(#pL>cy?njl;h_zYTLI>s=X6 zwtG_e_qZ>@TF^VuKcghqqYOLPs>r!yb1nTnv@f2uH1E;JN{ zk8#{(s)>9uaH-EU@QebX0VoMum*3D)8<3NSUi^=uzXzeix4GkfIj*m?*MW|jm-qn^ zc=2%(AY0tRQm~L@U7(64sl{oGciN~_8W9i+Am@6ve0QjBCxQnVPBGi#hpi_@R`Noyv2a!4p0Np7^d0KC7k^Vj~D$yhv|R ztaM_HkhG8+&$-o~x04`W`uUygiNQ-j(u*AKi&Ap$T6X;$$I;#5g0ktwfT^LIPEvn9 z$ZA~$gGVTrk`E6p95;Kr3InjOZ>paZ$lQ}NwFp6}#2M>WmFg(x*1ArHk=zkL?rgPt zLMr6x;J7B?b1$#xTkFI%x2iJ5opdM<$4`ngfR%4INmb0JPpN>@7GZniEdoBcjoC=! zJ~3aNga-w#`a=Bt-QfUM+-;@JU|69qDq<^I!M^I~rN zP$&bfz^+NDj0e}GD+S}q_sSOaGRxe1xyK%(d?de^o}A$dNfV}~_s*AGgGx#SfLroo z(l3E$DS~%?rXbA~e^A#zsL_bH15w2uDut2ypyE`{R1=mDobZ{qhJIpjMqO~E2SIFD?9+RFq8XJtP`=r8RhcdSa7`PX-qVtkU*jP z2@(WqQe{?milRWGFCVtlm|I)&vJC|h??~<5*>-L@(T-QY!4G@m0b=)`(*Kn8iWZbv z8W^XxUzek3enNw4(kl_H-TikAzp|)m4ZQp~@?N8JB|mk?NaxlFbML=HX4$jLS!6z< z6I~(MKIp<{WO#S3GVcf`||S%a+KfU`^)v|(o(TMT%J^~^>`(t^yyRyWN;&c5Uh6NrtwbB zYpVx&Qy*J@$@8U{0w_xhF`Zw1Bo9Fm@`hZnBD_ceQ<^G*d?mcTUTS~(aMCYZQKfi3 zKVBy3;L8pM&8Ey3s-fhy6y&}ZDD^Ltib!$n`uu=^zWn2N=hzpWt9!(f=i*UBCs4$f zX_*6gN<6WYdN-QvA0n1nz-9yp7~IJ`%|&bxUfyf z`Nr1QNG|A8Iww}q0q<)e;A6IO-NT)Q=BTJdw=d{pb;o2nM3Fk0{3g2h-v6PH_bznV zv=d0lXxyi5qDiSWYx-U#ylF+)UdlDD;-US{sVn#F4Rs=CoFMFST0ka^1$tC~M2k~pIXeTDG4fGI%8T+hDgJ2=N?a4}<`1xhoxJY@cC zhwqjy_TyS=#wKiOxI&D4%05e@<0oL=L3$3vp_yhQw-a%V5_6N6>Iu{};(%OE zB408a!F(e~8W`Vc*r|XzviloFL2UoyJ74gPySzX*)OaMWbqe2doLt*`xX5+AxSOgF z0}tLt=^|g+dV}X&aL@Ct19yCiD;%}ubN2!Q%1#k#;!h=C=ELwm3Z#V%)8x83WoW`3 zECa_%!U4ON010wUfn)qPcu=DXu#Fkzp<7 z?d1+ZLua1VTyqi~PuJHUCp|;AHb3260JkveBh_jPxKk_Aype@_ z`~_2~L@wSKxDC0x>-IkiDAI0{2fAnRD1cm37J277`3UpRQnfWFv_hT)IGy+-VWV_p z8PcbD#Pv0UjnlN7EP?!GtyB|q%QY3$O{z!f(=OeK%G_=k9|WAvw`|6}wSf4$TgxfL zd!}F=wkf7q>d8}DzS68a*-U*IO`(RKrxW8qKX1@#8Q@lvCRho8KCc{#ye#Lc#UEfeN_NQr! zvRg)Vc*D-z#cMw&d#Pm@JsXrobO6x3js`G^?eKL6_`4)2rR3_c+FREYa6QqT)+b!H z7jRP`aZ}H`7VmocG2jYA0{KfG$xVjbn^uf^?(RSInpf6Fz|SvznxqHPkFrln{@u0h zVTMFg$sB~4dvABv0KAFZ-~i(ud7utC?$U z`$AcdH>jqBe;e|ogMvS{NetmOCy40NlCYsoJe4suZ~3Ux|zrie)~J;^YL@NoDD02t5lIZI<+y5~k+| zke8u|G^|3d`p_{x{(M|vsh2$j#;RjB69AzZ=Ox}k74>F z=^sBU9`!CgpxMmc@sEo{G_W!|x~r2;PJe-e zWX1X24skBHqWucg7{)%4@Pd*7X`8i9;BlDe`y`t20Ia>PJ+De92fTm&#w3E0%nd?l z+*>e)vHmEwckS|dLoD7tb+)l5ypT@s>uAuq`i*OlV62LN63Yfj2#k{}g z-CRwrph~fmy{9#lxiLrWbAvjFQS}WD%ctc{5>u<1c$=dqE>53(X zxHlAXJg?gs8%|O3xWEK2rK(TIU_H?ir`V9jNwJOHRHh~qj@waOIHP2<=1SUbQb0>f zra;82s0mNU^Rtu8rC7Wqf?k&-ui(+MhGALcNa%e31RbjS+b)WMi3)b}(S{=vfQ@bu zrAEk0u`n3KRQjE^pLGf{^OST2$oGzo?oyP$PeauH{8!(YPCbDvoXsaNp(1 zva0j9AZK@vtuSj}ylk;<8YuUQK)sleq32y~cLA-I;>3v2+QR^kxUL*h`9{NP>Ax6P zkvD6S^|CKzv}dIE#H+RcLV#POIuH4mH6>i`7^^gRmAgmwH%;D{>!tFYKEwm5Q!u3k z?+bYfbZ_zpy@BvQ2>hf%o=YC* z6el2UxV{$Y|IT)TY7pPqqK=Nda*_dUw^w3zPq~-K)x-T%nv1hDrG`SDDt*}&Vz6<4 zz?B}*=YimFBz1dF$$ABav^Cdl8Rg^ek;iHWT(xrJ9$DXzOfitW2HKB<`&&zwC(Gq) zsvV;RI|@U2W9Cm@db+Q8m9GS-_R8e?6*e8qkKFPY7|48 z=i?3LS@AS!u9BtSiPHhZ5Hd!Ryf_9QotS|h2~vmtf`H_E7$U?`oZqfqI)z}!L&|7U z(m%bGXJ(bEl2cFYgKJxfn6t;o9TCYOCM3d_bBk3) zW*WNrBNC{3c9H>i6eE3{W(n^l2?lGr&BvB~ZDS6OBrGvTS)oh?MMW}J1hWE#dxC>; zlwUY^n9zxcZTIu4HJ$9yEDyyk&s1%^9KZ9_3tH9f%fneAkIo)dXl%~0P6Jyqo3JiF-``GDg&6obDMnV9WXGFEfPp&DJ02KbruQCr}uhzP(M0hqit zo1TpMD^A{)ET%*zOlbV;gQJj>?BqyH!kE^22UMBN?75&>FjjzXO1OyhtdZAVIrwLX zyWeQNKQDDtjx($GsOPD?!N7rQ{rm`dfEKpf1m>T~_lC~k^+d_H+YvAhf#C`NUF$ap zhSmPJLljA01}DxNNRD?q)2ksm+$!7d+>XIqM-yPcuWJjl{F!p~&?)G>@E615_Pn|> z5S09P<=ijKo#RizD@PIZi`-lI2af+}N?PV$wTjBkboeFRb3dz*HS|^a)p>d}7OJwX zGd&2N&!zi+B?^qsl>;hzLFr6R{`I~0%&O@&uhLXwBAWI}Jdg=i`fu=2yS-)_DRJ4c zr-L|48|x(<&Tm<;XtoJkt<7q&jbZ)y^f}}#CJ)E>RLH4Uol63(nrT@BV++dAU$tqx z5+suwvhmSi#|wS_UG0}aOL?ic>jHL`cXm52p1tJI{1c5NgSvW57ybM$T2M z>jzk!(x1%?oC{D-)R9nuuupc;*H`QZ4B)wUmh!blC+$K!T)Hn%m7iM)SC%&!JZ(J2 zCzf?m)=u4MqH}1K9+uCw$~F`-jr##0R%VE zjim>VEAPIR9Dk$&j2XNjNgUaIrOrPaQa#Q6?q`n-6khXoxACqzHF)dX`aBxGzjfN= z3yiedm9Mrpl9N|~$gCwUaRSx1cCyFXj3s94xG|6?h$hC=YrgHwP_@4j&(@BfWCi%C z`n!>K{F{(=9q|CpGL_X2v3#GcTNMtU=M*(uo?qU!zjEK@3ptKamPk>ZQ{-ryub{O0+aE7 zS%$Yx_1JLYQg{PvyP}aBvugTUd>@=X1$3qzN%7d}#(<@A$XLOl2p)i_$~%^A$Wvbz z-P}jQo0>VZb~qpt3O?7PG^;jd8Y<`|`rHb-ruaLfqn>M+Km(s!u1(#0L=LE4CT;EV zgffszZ;c}6EoqW_dl?=sY@91?stqLkr7g{~KlK-+IXMWUYSKn60w!qBysRW}lZm7$ zLWU*|->z4i#w#q76u&<p=dHKN# zQAPo%Pya<-+ML!Pzbx=q{XH64hoHq>X!V2cpTdS<>WG=8gpkB}DzQ1>s>3XacVVJJ z$xeD1hyCxjMXmenYC!0h)Lp3s)3?)ZKJTZF`oN4WKiqc!UcBl(W3~vpQT`jJ9$8R} z^@f)C$(kv=@{531g1UASQxS@$7E#yMoxeF}a!4gN1>d_F2L%B;+G+l5DZjnm-Ia7d#n&-q;5qo?jtL?neB;;@737J6sU#~bigEx!+FLN51cl$#=B6Yl{eM|% zv8M`~Jk=YP5}1a1wQD~*g%^fhy;ePTO6H;yQL8_ZoV;n27L9$hOuq8aL#n zsTt*ona`yh`TC_Sxj?hlCC720VG@Pw^4@N3>vhEod*x?_8dB?iji}V*>PS9dnOdPn zhsqyX+gINL$=!?>7OeO4^Q_o(O*>(cp^D;VR;t1#2?#=^Y@_S9Xr`^9bJko3%Gb|o z-V49eZtGNWmXoL8EXGnM|7R0m)w2N0`X2>slhoCDv2bOuCY&QzFvq1aDw~{}T@53u znvXo}z;RC3Sr-ch%wWpXfM~-0dF{b%#qoS6&CRE*$@%2oL_FHs2AiScqEtAYH67z> zC6vr22mhq^N7qh$`{`nn~TR^ebU25X0=7#dHCW@P7+lq*-fwU zxVY90BX!C`0;OP$fsW9x#k&;b{!zHd65847y_=Jsv{eEledfS(r_M=Ym(=ct+S|rQ zw`X7HO)zMr18%F;TWPwWfbzFU(x2?ER>8weiIX_>Psy1jDnNxF-~gS0nb(ORFJFe2 zw*+S8b3!Ke|LN%ieQ4Tbpbnww<{Z(4_IlRf#nIW=q(p4{Dt;Ei+h<)B0AB(D-+ z+50q*hkNpmIKkk_%rpN)SB#pr?R`&gPwQz+Xff4K6I*UFCM~v8Hr-v`Kg(T-P05D; z8eTe8Zb!J=eRz+JbboWaSfJ<(5Yf=F#;|I9aG&U^g-rd#ORG_QQ7az0CmiyYBz08- zt1JOCJedMo^3g(PVQLU1!XMvY*4T-vB89c74lyQr^?&&m^wNwVRFlkz&+XsJfv!Ta z+X)bhvgBDhzHQ5Sp6X#7xWtn&kwP4%K9i$``>e2E^IG&2GUQgxS}mC|BRZ09eyw%>7hj)`Q#YRj&r9QE9RJ-ZMUY(!rIWgA_QH%2x_Yo|V*S*E#3Ij>7r*kIj_ITpB)DV!mIfDNGD3l-O zRE4G?3(Rm#9Mp5Fq4D|lNT!#yduCk8T$YpLq49+rZJMv)G{*NgY2tp!jK@2DV(>L` z{a8o^lXT(J6TUs-52cV;`*r!pcV@ga3SeZ!rr+U^Ejh={xIvQ7#AyAAJ1kF~x!4$Z zuATSdh;7jQD!Ud~1OMFRiVx^Mo?n+AKvEeT^OHIFvl^<4d9~}`Epp|@3)-(N^UA$r_QKdF2iVAbNV&NgRtTO&^$_yNh}G z!j}4HuhO#SgUpR^vB?aXXC;UrXQ3UxAM05AyxVGXPOE)Rc6(@VE!Iu)+CP|!2iVih zU|WIoRy-1V4Ej`lL{7U(vdm^xPbqS;9CbbS0x^o|nni0?vbLJeF&Q#j#WYNEPs%>- z4;@BMI6kBrjcF&AArbkH8B@C%QscjD;Y`~>o}pB;u2QoUn)&m3`+^A0 zJx8TmHZw;joM(~a`IK8B!j>n3c+NoM@jM#PiI)_oFia-j(gBxxP57d20 z_WaF6?HIcKw(DF&r`;E>EH3Joe0Rvt!E97o%OE=+uLfFQ(23HA>HTgRol36ka9`Jd-|WP zae9`Ms7Z8_D?=*VrdaA$$u?LXT17uA1O3u5>t9G;S_y5W85xq{yqOhpThtSdx$Rtc z{3G`F$u-5wZ4pAgaS-KW9Sbq+GE{W$>s~fL2Nix^r&bRiUCZ8jA2w>f9JnMy6nM0Z z<(;|Qr>Gv)=L6yOy{xT$C9a_sqcklck66>b&of5N@_?Cdm6r|)#zr{LU!wJ$KIcr4 zyq;oLRe11QjP=JneSPUXFW|_P;+{pBo>|$H%R4_L=Z(y8GI|c24uZcp%`&>U%u0`L z{ST|5m`a@&CeJ9-d@pgY{fJ#h90J}wiEV1UDxP+Zhl9pWGD$t_H&)R#J87;h^y_z) z(krdf76)eE277hmJ?rcL0Qg4X3XmiZ72DhaGlc^Ixd#WHM{(*ae^Kz2wwt4B zj8ZW&TC)=p7Dokn&OkXC$KYz$2FDRkmg@b^U+t^awyNjmZ-_J)EFLXJ2`%BfxGbjI zY4akB0EcXhZGM0Zo-#%-Ysqczqwy8#w6>NBgHF)z@`E$Tjq@mOs#j^q9)~?E(tKN^ z>sQ*GmKLGnN1JGHrygE%27N2O@K3{8^pNt>(QmWC{ThoM*Rwg!Sb5*X6m74c3-w zsKIii^>)#pTZhGA@VF%^vb>(i^DFNKypWl~J7V18H070-+owF&Yv4bIvRz7-7x4Mf z6&yO4+Xu4$06d@YuXxjZCPm;a98C?#+kqL{3GQ*}Uqk5L7PYq0VU|mHt;`m~f14&m za%V2Yk@tBx9AIP974;X+0N_;bxiUA{3Nqz0VzsN7H;S440A@Ep!)j4;uMw z0Kjw5hFo9~*KyCj6WiZw^Gep1?kyfux($T4m<|Im>9mfXoaVlRy!dp!B)W+Cs@Ad0 zuHi{|$UT8Pj1l^NHS9Wff%Kg#O1HMOvp~_wiCbvgS2@WiziRzM2bS{FQHruYR-HUQ zwC1V1K0xr-fiLbgD6Lx129|X)Lh1x$b?2uYtLoh=!b_!FM+mjH^G4ixG6@w}b-^4Q zpXFWUhlX_9XNFjzkBsk{HOm5dBcFafzbfh>(-9COWCTSa`fkDetJ%V3v}jA2BP?br zoR=(8x8ixYv7F2ye3(ld!Wghz^#hKX$;Z8E+Gz3-aWqieO6o@ufUUG+jGtdpeQUIq z!9>1j!Yh!fHsrTC!1O&&(>0|9nxo0eyE-d*VB>H90I&KQ^^&q@n(IXw`W}@PxSB;~ zFCbmp+i?e+kJtHEK)Yee0lCTSF`9g6H(-UxRn7qXIH^3Wws3lV@5l44=}@(#VJeNG z;7OI-RE+-s0`~s^IH^ZZ#(|O7C*F+q#xN_?gj{uIA}XpVR8WeeNCRpU>58X2Yy*P>(C3b{>aLz*mnUfqeqF!k>rY7ok}|u1<#WwUD=i0N zOpKA-4n-Zw=aE75=aJaa`0y)92wI8PD#}aZKyp--VaIH8DndX7iQ#&huI!Pk5J?A? z$Lm?iw8n{8zCcU>RQ%*;nl~_CoO88z6aPjaVW~A5RbY~`Sz(5N`D(UCxYre zQTPE@2}zHrxszr>uIzMXr-Q)v6${OVWK}G|G87(3>_7c<#GHu)P5=k}SyP^!b5!SP zZWhqBoKrV3U;t9MZN#_C8?eSczokPg+Yy<7#{HlU`RPrMJb;6xKZL?g^VC`HVhRM0AO-$hIZ{5j z{#7}-RUCfs?MpTk_W=Z62%;AX~_vn72rOqjxFoYC*&cPS^;FSr5TyO?|&lR6E zAj$HC$O9YHlZ^5K9X)yUtMSUNB2`oKC*}VD>!o0%k+US9nX^+VT<5yx*sKN_q~W3~ z%8oE8vRp1oB!nqLka!vN&tHCOSy+sDSYDaH``xRP)t&8~oLtT2&f7$Bpevr)@5XVO zo3v{dosG1aWQoue2^cs77~paItB$x!h;CGZWQn$yk%s1Dfu4X4rmk4rG9M;jt>!RM zDbC@KUflKkstfCgq1`KajT*Tb`LpaWM*k6*(9y^YKvQHe2 z`N_q3&aE3meRi zlHH!w9rm0FS+cnVb|a@=c&{qcZdOaiwr?=bp;;JZw=q3Gt$Nm)Zmp6}w8F9OmA=g2 z5=?mNc*b*{IsI#=4^h;Wuc4gXku*kFKhhYH6UfQt5=!nLczytkk9w~a@bEfJxx`cytbKG2&f=KW- zgpVBOl31Q{0ItnWWhj@Sb{bvViI%~jQ8jz!%fA{&5O5Rx6M^I+uic){TNdeUC< zHH;Im*>x)ipZyjclNm7g87k6_#fC@>I&s(zxXm&^rg>wzF(mF=V!WWVhp5|*xgR!t zD;5&3aPdJ4N#sTx%BhswoO9T7>+4j~;!}4ckC~&KDc^(CbB=#n%A^uZ=ut_Yqv1~? z)+={eS~Ajn@wxd`K|jvD1|3z5?4D$M8C9Vi{HG@*^ZIen`q!H2c8er3Lo1@eBw!GX zOC$5R?i`WR80pVk)}%V6v`VUE+NjOO(pZk%^{b-dqK+!Ioky;xr~Ropd6`|<5_WV$J5pPz8*P-~*CK#yL3TpGxJY z)aBVEzDuy@0AaD;12npY+6BCp-WIl!NuxWIvjVuo0q@Qa*0`&!N@!)=v0Th145eX^ zl?#$`dEoQg+NMuJoh4%W>vtzAup|<)vb@pC+nO?Y1Re%@aoepjEkY)Ak^I*xyHY!4 z4Y=o_=lNC?(woTML{{@8a~yFFta<6{^&ir#+UXkymM+xqA9<98S5uSEIlvu9f1ouT zNK)mIc71K2-Q|S~^KFcg^JM=3Ox4XZTWId%kIpfKR^LAT+nKYF4{?n9R~2V~Zrt`=sJXhel@#QfO&xX-<4q~#Nr*vU&_vTBIaubfDN z6lIG88<=F3?cc3gvhf<)q<0BBm?UlG3i)_aFc%mH-<9=U zJ$*fEI`Bft7;B%id5F8q5WV_y?Oc^H6=K!nUn03tr0&xQR?cKQXp& zNAY0s-nrw5e94+l38U&wCtJ3-w2fz#V`basw4eaW2e0+5snXU~m7|S7F?@}YlgDnI zYv$WqluL+0Tir-Es!MRXifxaKukK3*+D<`W4h}20O-oSoTHHt)6pA?zEc>&QkGqZt z=dY!Dl&0jhGMpo!-9t61q_9o6`I!jmC|#$HymB#~J;A8$rh)@;1T#gsAMe6P`m@I0 zrZ_&l`qv#D(}g21mHAlTE&8m@#FS%vDkq^S6=@e!j=rvW%N-(c7umGe_q?n2uou zyoOnD03#nT9Cqk`ty~^lE~W{VSUkMk1%PTk(w!Np7E+JaYpOGW;)FWq1; z1_0+h$>;T~mAH^aBV=tL5RKD0s_l5~b#4+NY@71d@hRIHAG!wOPC4pHs*LW8YPWN# z`z@rgO&Ceu^v6US}d{QN&BPNb-_Q47DIOw31$;42|d)GXd7+q_O#7|_g6e*o|&W& zY0xQc*N=Abx7vLBg3z*#Mi7iE44jeIjP$9aM~X*+&veftGi@*yk-_Ca=jA)FbLo-a zHJ$d^cRX@J9p#m>`-m}*LHPChQ5d#q2ssU5YVhsy-7Xh7QbPdV^#1@g_S*?=7zof6 zK@bZLGx9I{CpqVwlj%!sb|AVp5yTs7mK)G8WHbB?2&;PIRu!n77UWR3+gw)n#}t0b6Z zC)XW&@$~elWeky9lL=M0kz`oLU73CTK8B}`2)yQa;s$KyNZAUNP(4AwJdet;nzJFe zzM?s4B@tZQNp$jsReORON0ZZlGEcP;yi<+yV-ZAC&5lM^^lnswI#d@H<)CM{NTZlC zm6WyuwsH@z0Cw++jzo?~?c>bkUB=s5*+Vg7z~kKd`+C-C65yOm4-i+mk}(pXWoJ3s zWRPP7`{R$olm)qz#s?x{-GBCi&#~Jm-XFrG!af*~PC2$8s6Qn4pv!XWsy{Tr0jnDfHyBu z>`qf{)M32dC%T_)wDPXlSTEls@^Tb|f!95$vs{EpBD#V#w}A^=80{5UbPP9voOHk^ zj&ataQ|3A;H_A(NBZFnb&XKa)@X{z@BYF(vXTLQ=6SR_t5(kbIS*~!b93I0R_y;@= zMk-s2LmCq3&InWXW&}tJ4355_j8k4<#zuzP2wF|ca`C3$Gq7gIQ;ZDMMH`KHWR6h; z#KRGc4b8X=5s=vH(YVD)5M&TEtsI~yF-VJo5an4x<90@JIW;4xNSw5uX5F%K+1nuL zob?>k4U5EAWs+%QldNu4MsrS0*yO68HOm)54DAw6Cz#CcvBJhZ#Pr?jI&)F9Hv-@^ zF*VXhjP8(v7yF|;VCVeimI*E`1eU=GMU=CaC4p@8&pE3;V@VvZ6q7+AA&MX@8M|lc zno+tZ+c*@ZiZd<3?1(&}RZ>07s82ZOo)7Y?)5Ry0kRfJynRjJND&y1t0IyYVAeq`b zn66Lnt%5vpm0-+1@jcbDI2>{8Mq3x!C;j?ea})uTI;aGJj(dK7v{_ivoZN{nZzl7h zM7N2jvt?G22v#`A`?xB-SPn@e<~*KBs`Hp~lS>BZ9b{i7a5{d%#&^#wg-MaD_T&Ewl#70SwlOKV~vw*4tFTR zspm#J_kBIQg=Eq}F8iXUx1sx)%2km61HNnF4YK zMlco0Bk(w@2?G+-uHzU*+>Sz)Z2Z{u9crfqW1gMdgt*jUmQN{!vN3JOHQ*Tg^UxF6 zcjwZnT*DvP#lX35C4+f!GVKwrdUfn7@n79YMA64-BQb^ukN_BD4EH$X52^L2gfk0h zi~<88ZNu#j0`=%}2p+uFX(V*nG*oHP*_Pl+?6b$_B7&I;INI1Mat~3SdeZEfOA`|W zXDWvz#qghlT%$xhF3mC)G;K*Q_n!G%g!4Bo(?J2yHrjk%86h;TEFo(WBSo% zk<|xuO>XmVw7X|nqD5`!!!5h07(aPWbKCK%GRYud5?NJM+sQ|A!Z^#8+POR~<|hM= zYU@b^F-06wN+g9?M>Jrm&#&iH=AKK7c#YicAxSxsVp*8>B>Lx?rk#OmN?>NXyLcm2 zf3vE`BM{p|9FQ}}864x%p`I4`(Vc@5V~M!(+0*ZH+>cLjR-9(tS{M0{1(Rv%=ug(7 zfU8KsrjFwZS~+9NuH)F}xI7H5V3jOrK~rX2)}E1 zEtWmw8+RR`Wq<%==QyF%kug@0ZqoYlG%-TXzHnX2j(>PMVAT>t*B8dw)X5$h_paih zjt6m!n$nH|3<5b>Ll$4NKLE1(^uBhu z90V+GU2*oI&kP4R;AMON0Q$36L$k*7EQj}thXfoG^r%&^E~A_-Snh;~f|7m4Y0>%7 zMz0ZTS-@{5TUpq7V1hA^$G`Qbc2$VUMPD?wBip%^hA=;;<55X%1;jxv3p8F^Y=}rl zBe66P4+0~5Xf~-i!IOmU3$3Dih zovr7(-5X{I!tD7@LwaMespo5JheHDFbarVLHaJy0dz^h~^Tf}YTv7YkRf0qNwK20S zxGcHONp1n>AAs&^t6RHB$K*4@S&{zIs}}_19Ps>bIpp;8r{)vp!s`@+BO@WVVDNqF z)HczowBrFG5&1Dc%)7IYF^+$gH7Lm(^MjLQK2zJEjU#Q+?UAGdAxO^yo}ATWo+Oq9 zKv2oQEZILlU(A0>x#mvMPDRjFSyhtWOzmO7`EUsCPdN0ZB195Lk_TppF#&J@Z2jY& zqqiQu#+{6zMs7k$2ih$swpV!pkmnMSChVSs9Q`rVifm$SrbyX$;gqkNfw$McAOq8_ zU7eO#1gims3M(|nA(#=8J&!#qq_ROC$qa>J+P-9q5yG#0`U=iVQ>HZBSz_W5a3La3 zFwGF&0$_;-Mg|GoHh@Xvoc(INXc_|}NBhK)6!aPEpRa1Y6K@e1qcTGhoJks$WmBKZ zrMPhL+e9!`GQ`F6H#r>l?ceg|sZH}D+HB6eg&N&rg%TK3Xm}SSXQ29H{A#6)rYo(d z5zB5^!xE+;s`Kq!+(kv=w#{Hs1NXcbm)b8}>(xE1q z(Mc=rO?8-@DUsxforsmQx2qV|jH`CU%Q)b+X<%xF3G#_J@f3+pEEOJWu zRSZ60oB|Y_oF87ak~C$>p5w{_6XuI}P)5XK8R$ka*W8nugi6D2`aGLNVML6fR~W_z zJm6#Vs8soFJeLuKwWqRb zh|SEGOA?z?=GindG?F)A9u%)aNhOC&b;S>E(V?~4k1iRQ%;84fN#y%`NtV-DuHb(;h^UiX3z&zGzxUoiR*eo^;WqAI$gfr37rc*j5F@5+rin1V>c zNfaonB=Db`%iLQHoRV|3x(+eG_c?CiBdw>;F=bDXLQZ7#9glCvH6wY3NE#@lA<0?h z+lbKf*PQ-C`B4-NA#AxL4BOuW%TdMw9;cpp=iZ*i6H?TQXj5|9MADeuSIqM^;al7J z=Bm#G>gphw5;616u7#PExEp!nkU2RR6>3PPEVCXJay-zOQZxAS1wI)dw-*hRcZomN zNJA+ZKDo&M0P9i9sgjaRg5{)Dg(51`GcTL_!T|Nh9OIt8pN&X{;@rit(`-aE^2rEt z!zUnTf%T|=dx#!5OD)5dfRJ#`I)T?D0uDZ&wPrhnh|Bhpq7)2Sju!)-r=?SEvfSH5 zttR_MxmN<&OE`H3)=`Y|4^BH(7+{u3?jlUfaV#QBYiOj*j7h*yIs#5{xQ>I?uLBe# zf0|>Aj$;6G>)WT()YVkCG2Oku4%yD#oNgF69cp)HI+UAX16*w_CCsfqm$j03RzVm9 z{HQ@3XPwhILwyJRy8}AG~QrVEIH}?K=OUDRwPFIJ*37+k_cOC+OQ%|C!B>N zg-dcRwGGpj zmuzci$; zs(TTSm}9R>Yqn7R?m~%o0m;un-|_dVm}F`8Tu6pYgeb*Wf-qEL)k)5KXV#)ouqjxM zONCWqEHVKSD?3G&%$dg?y>m}u*GUucA(<2`VL9O7bo?tz65B_Z%Ws}B8yE-}Uik;H z0|y-Q^{Vj&jh*&|r3?h(=Mn51hIae_o~o=Pb= zI1SYL=bTklxVD)~%CZ4FoscR5v8e6I&NGg=Jl32NJ2mWQeDg+HNea1X6%TgnfJr0M zr>$Yj^I#CKgX(<*j_MIja^SN+x0X$)?yEwf~_g?QnxKs@Is zwtZ?Oyq#r{Vz#$St8iqFX`>S>9OveZfl@nQijM5uq#LaKu`5g!RoJKlsV4yB5!3$w zuTwTzqqvZkoCRrOS0Ivd4t+=0)7q)VEsDvITS_KE^QnNVFks3Qu^qr1bJrgIx>M#c zdA9MYlO4hqEwO;(9s7L`^ry78S4L4Kv_j!FZe&ufqtIi54nZdw;-i8ocgEA17_;MQ z$U>_6pI*YSjCpnwhJ?WuONW{=$ioV#2?{-cJ%1XCWNDl1#ZJ_83gLe72S1fX_A@A+ zIZ!-)aAX@!HiO6HdHgEITt-Iik~FLp0m%wFeqy?8>|~(O8)?PF_Rh)-Y+G@eSr`Gp zUdND5a&yKihz);eWJh1L!WHo#;TRl)jyv;O5qXE~(Lue#5DwvjtDb;=N=aE^c_TuR zM9cTE2IlEmyECp0#UinqEs)JFW04h^`ZiRb@@SF=b^AG&c-!*L8x>+Zbf(J;rJ`wM zhs<}|g5Fq>dFjE+1qY7!KJ_$^PimoSsF;ydmrE`$DDG0Uc;@wG9w$pyNM@pRzf~+ ztw%FN(J%!f^DY&ojU@=V^*QUu9P>lfBa)}YX2i=H{{WKoxCL(mC>xBV_*WUQWOP;B$^o@~Gqau2rRsi0&X#%*2&e z&Unb+^yle9(H9z5WK9%CFfJx=WO3z2k%e4i9FE8QPo+sZLhwNoDYF62WwMpL$p>xO z#@wDb=sD_Yq|(N+Bods*9m6V0cvc6n_XCqwRw<>snXn|Z;4iB2{xowt8qST97t4;< z%ZzW@9lZ9EV8HX94u4TeaKV{ofk1fV++vIFlbnIcJa*=tbFpq?fs}y+iT|Vm*3y-U<9KA>43kD#2IXQ0$N=Mw*~tX;>BlLjTu$3kJDBa3c$sIC zJ;pUZbne_103HWWGtYm{ zl^e|7t!frH4%dxywDXYM`<|oHr&fz<#o6^Ko^yG19h1)_3lwI?#cj}S`?*CMc?Xlm zd*_<39FdEm#JG4_n`S;bNs36 za|cN|4P}=3qD?0~R#3`zqirN)aqHWyQ<51X zY2HH^K4Pp7yzV~abO)~-^rtPn@ubp;6=!m-Hq`@h^(U$09M(zB<*IL(k}J93nHhf0 zZX<7!+H?{C5O7&YE47F?2RX+gqZhMk2IA#~yfb7p%WrNWUi}q71MsGoO@e7sAhyh* zWdXA6J$mzx=}%QFbk1U3j)9H5psN*OkVogZXY~gZO6?TVOJcg+Ka_-_NvDyplDJbQ zGBcig4CC{wNaZCq(kjJs3dY7`5M_03*+s!8(2_^5@&7D_f$voOA+oAseTOoaf5}~u(IXPSowGK_lpDc{LF?d5h=-MbsTisvKT4DngPbIjdM_9K(bh6v&){{Xov&md61liTpBC+y#C z`$Un-(+JdwH-i~abMq+#A5VXJyF09sOK9;)Bkm$5hUf*{IXv%oyuZhqhYLtK+GKM@2kwc5rYR8!`*5p~(0w@n03xQ#K>{O37>u#nW012*+3G># zJ-F;C(avrylXR|-tVK}GDIQAXkQ8{O-SpdLiV{%Td3m} zOCunAt0K@9Pu?jc;B7pPnInVKii$tAJgxSz1>6h+LlKOI2R&4S$s7@%N|WtLW{(u$ zK`7lEU_=3tk319Ch3)U?YAHNpLKpmChkQcd=e=FS!;X>g`2 z?mT@z&MEODJk2Uj6#c?w$vay)&wgqQr2U)RycJmqg5KyuB&cK}aK%U;c>5F34^iq( z5gAnrT}>^^6V1f`05p<5d)9Cx_wHqQetZaon?o@DIrpt5x4LLxx44gC3LRK(Qp$M; zC)6G*NUct3w#Hl}GOSH3F65kr5t49zpNHi|&9nvxAu_m;C@yRH7o?kgWQ5xW>!RMa29^UoR;TD40i)V3lZD%YWx;Elw zF@?7RMvxBe)Qn?;)1O*!Gb4#6Z%$rS&ij{#~GQ7X|;yzbjb&vgSBSqNd%S266Wq{B#g%++?bATAafz){pa-L z|>NEW{{reKBw1;a5G!O z8ZFDtFA9-t({RntZ%{MO)~DIK8p4~A5RHWD-dIo_WVDMLg04C;oQxksp465ys>>ja zt~}8R+>y8dj!7Kx$m7?M?MS=hFJ*B7wUticESO?J=dMp4p48E6EO1YIYZQ~bQhegv z46x~*NCUTDTIr65SF?(aq)JL%$s-cbN5DWf?OvYvqFWXMFm4M-#5U-hHyP>NV1bXu zq_LXPN1IP*o>geu&PnpQVhQ26$mfh41IKE&J*ZhBiaAy>Zh?YZf+N~cgEGREk7!EyG1~uq=i-HtddXEQIzv^N&vBwrT~6OUU19?Pqi4tc}YqeQQSD78zbP zk~9nllPrLhC$@TL2e72LpX`FkH^$>=k<~whD~_Aq(6XB9&*{u*yMJPEJ7o0PFfx_OKYOk|7CnjzY{; z##<-x$m>(ti-{E@1}Rb5eC06(RUP*K0CeZ`>E55`*{jNmmr~jz?6!*P(8jDsAob2c z!5GNT(wDT72GV3k;jXnim5MQEZxWrh(eoGt^(2yb#s@vkLN4G)G!oq?1R2|H&+#A*lwAqfDt*VN;+T16!cO$=)yL6GSnW96PQdSK@x{{Yubw2H!46!et6Cq}kk<@pqg!!$t(j4JwB1QcHXC{sLqYa|92YSCjGiG)>b7uW zAQe1?&UobKHGbY(UnoRf-bICc>14MG#d!dbybSS9vWev~Ts^FKD%eylBKduo@HU*D z2e9?1MX_6`Ma8+uP$Qh>cQ6N@4i8$oa#4#j=Z(R@k8bRFl1=`OmbW59Cr|+jdix)( zO&dsexOpwhBJj?vz;X_D`jBuv$JVNO5H#+#^TO{LR#5>zF+F+Lc!;lk5EXtrbW!RVY|NOoVu8OBZyI0l{~NrFcQ+TqHx zNcQ&)4(1~SHZi$+f~VWkriRI2ja~C18-u-M`IS@*{{Z#B$)y(#hcx8ihT1Ve(pwm= z4bBzL-OMt35zzfASB3~=x^|Om30LjXu?@9|``O^0fMjRhsaxGc5f8T7IH%tvP{nT1 ztb;fJ0iT#D&Q1ZrKGk~QM-tndAW54ufHRZMGg?W-L~)dwL|$Z%gpPHPTg={BC>5DU zLO{>tGf~NR9#_osP&BI1IJYh%VsHry&d^9C{{Spzw!?uG@Xcp#q`Zu;8XZp~zMOh?MduvjU=b>n$Cv2RCQU3Q@fsn1ljWaKqZ!0PfG#$VK zM%-|FoR3V>+*?XfAyF;M1}hA9(U}?d9FR#P)DAr=yfNIvGFy2nBoH!%kbt|nJgN*bQ6!W@Stci0j$B~2)%tq4qYI#rBsX)~{^ls)F-Ti&yT$Ux zdhzH7^{D}pG?5EL(1<^AF`IOZ#FAGXMhWTD(y1n&yHWY1lHI}(qG61JGL3`k4^dI2 zt3fN-xdGWvu=>Ggk>9TRh5(|$RoEWpVF(` zjpTWa{{SqG(oWS@$>3FZVe?{G+kWtI80ob0Q56?HYn#G%fvD2Kc@&QYwE2W9Ozi<4 zOnC!y4!Fq+k=%h*Euo%g3>}F@+!|-vpyZL)uN}Sr05?c(1d=qfNJ)sKuPc15_|)rf zdo8p@rUu+f8bo9KBd7TP0Q&2y4HWF6QWp+mk|{)Fd5yk8zr->}KU#`Ihej@jIU>&T zr)sh5`Bax-79|npXo>mePV25*Ym1&V^tKNyose2 zv)kG=%%SIv-3$PcAW_ke7%Fmcf=?WQ#%5UMkI#d0Od^l{9dZ;#PoVBPo_m@?WQy}!WoVtzc4b&~>G%+H&1LN;Esi;)-p0Dzu(1sghcm>ixt0Cvq|{iDdY@|99e@P6|=k@WQG+MgZNsEKxbv`JwfxsE}C z$GPv&U=BZ(D^y^qGegT!G*QoSIEr7Hru!(7k;mOt0D-lRGQ{!N8onAhV==~Ld6`d_ zCQB-l*FN6Wogjwh&Pbd}iXFEyxnsDT_0C86#Uw85)211LVq*xoDlu9{n{1tkV~mKU zja;;nmGcmxId0fAM=Qw6B#+LHEyC4LK3g6?AW1m)_cd-PgwsVDEamK&x?8M_3r)8N zcO!V@;ajH%835LF@8y2#I9l2h9#vyqpy&A!&*xVsB=$NY?pwp6$!?M>v}bIR$(F7QFJP3VfK7kiM*(s$?SPk^*? zM}CtrX$rNxOA5&wk`8mbAmbef!Tc);RF%wJc}KL18PT6Ay;ouH7QSAU%p z;{bmyDzB8Kj5f+G);x%!QHbMEa=(YAN}-CX%OOjti8D;6Eh7%(4_eYR<0E*=Ru00Pv|C*yY@qYVAfMs=ML5lQ1+UtQ#g_pN z$U?DE)DFDk89wJdd9NGBN7`d1BDV#nlpy(=Z$`-E3}f3IS3pW^r+mM>hTcX?wZw7+ zD8MOiT;SzSJ+dm@y2lH(w$O~~Hsc{#uu12+#X1>exsWur?GgY$X;cP0=Ofe+&-vn6 zAQRlNV#=(e0TeFM2euA<{mpX8^Dw&Do>453eU(gV`#Ri7u$58IJu*i@-0|M1IJSb) zHbw~T7S}Qi1z!0WtskG3X&e#2>NC!AeLCkAWZkw7_>{6r&fh3z zV}Z#%aqM{f%~d!zJCzyO$&TS|-d*Vwix~aamm@HccIr4FLSlgGFNLAyx z%Wlp{Cu!~N>G)NJnI=*0F%~O`p#!J8toGw_bnJ48vhv!qx9Jg`C z(YQ(4B@>9G+RGoQ&p>){Q&}a*kr84tODhFPvq}Z+IiDPk;k|^ zC0Vwf!y_3U^`JkqAPQDjyu{^gxDuLC2`9mK;k($7kDOOP%uF2gNITGBHyXbg4 z^vI{hJW$UIDkx0+-zx@IJ$j7snz~Zuk(Fq@buBtNw9`!cRf7Dg$Cb}ds2}H=wJC~b zQyjV9^An5)Urc)O%~x0?xM}5_{^d#7T>PxL$UfNPnwBW#SD9IlmkO+s%_dtd*pbHv zr{i5VyE3NI>MZvWrMnf08d*@r##n(00m<2(ho>V4oOJ6_(iV}W z>oRLqiCyFSM5!27mw7A{dXw*-GgcDf?q>Pz?VdQ4c|==zVN`wGg(DvFr8c+P0+bZ9{!b z*=}5^R3=CARZzTUNY-w4oB{~|;Pn-y``PSX53|4Tr&!)tl*Yd($pO1JBl8tYW!}>Q z$qGYkcO+kA0mOvzT3qFZFaqFUf(SV4R$Fus!0$KC(Uo}-#DRyo90Tp`TSmy`l9XQL#(Pp!MyZh@Q0bPy zAd){^el^SC? zW0Kxiw{=^4mfB;Lkd|EJ^XjMiaA~0~Vv;+k7th`{?Fu&+9F-aG{xs{IQd@z(;xh}* z=gQpJk%$K>2*}7BoF0JI9``oodroOJaFQ7Bt{jAt6mlALS0+B-DgsFabu4=DI*LfF z{&b0i=&GN+$IMv&0Gv|VU3o#;F}?A~<*=f!LQ>*ZxI&ixVlS8;U^g)*g;US2diKsL z&3)vI!*whITX?~clB$t|yC=}=r4%Z0U+v{2=4Ba%ERJx0^tjB-84Y}XGgyBV|-MkX?OcJZNHI?Ix$YJx~S zoc2a|~CRb6|jbM%l7DGE^yB0)UxIMoS z>-DPANpj^`ZK41*LCU^tZY9jbvoCy(Mt!^fH9wymEa{lq5X#9ZZVKQYc;g2n@b{-I zS4_<$5;ct0&6sAiMJ&=VJ8~O_Q_%VYn(1!H=J&2iVH!yk@R;w`SYlwtVdi2PPs|bi z^ka}Q(+3rOEm9@EnA2o(rNm`qk<79_)s^mXA>F|woO=3mkJgF7xKnkQvRLLa7j}PM z->qAMXjvrtM01O`V&YW00y25vrzD(r>C@7jBl}hA#v*yAafC=vvu-0C0m(f70G!mR zG;bNAw4qJ8m`yB}$~Q`pADAdOJrA!LtEJ<#@`5+p9ivwBA{$mbjE%vu(C~4QoMRx= zQQ5)@ZJEq*60Ax2arE`cH18`HQNYrE>B}>3&RZOg)J1bJbGzJmStBS9mm4f+c$Gsu z%uarRy~a2P)|Nx$mw2ZUvjD0v0l@2?FjS0;4|>k?qY|)ZX{3sE@)VNAmp{s_HL<WLAio?rxGLXwn7^6pTmj7j`(tNIm)Dv>x&(QSzcm(owz04b;&J z#|%bCxt8MS#kMt?(PI&eo)9U+DFZp+Gg$EPEe=2OsXON?AE|H8l8B)09=dsU0-l?su z!dXHqPdqX2kt1bR+wGnxGpQC_*&1CiV-rR}ZgS4Dcgg94#s{(WsgYhwfwbgKGs2Q~ z`~E()Qr&@$SvIt9BSx%T5E(JaJaFHKN46tK_c7C>>A{_Aee6!rl3qyySlf}*#Tqq&{oX!Q9fiFe+aO2}CE z+k^Z(5;?{PrDomP*%&5CZ#*j;!bpNiBw{#2F6g7k;fU%$^d7v`B${ZRPcm2}TV(yz z3vLmlZk%I`_vW-CnI(qq>gMGHsKum`<%wyz_2-kWJD0Zu z?wsfJtoffd#abNPwkpM`Z&oK}2Z zRkW9Ta;Wf`Cvw?VIO@dmNCO!)E#2Be*0J87?AfkjW{>SIs0@8WbHNO_BiPp3q+ux9 z+J(gMLZzK{S)_;UHw@TSRUDFX1^~uSUTQNOjEyWoQ5ddeW&>*a`t;}Wtr$cxKrM`9 z$r7^-@hbw&(E5>#9)10JY+zgqi+573ENkX7Fj6o`2LrM7s*T$;Ta?mfFCxUCT@c#{ z%7$EjUbQ8>*TzLRc5}u;g^N%i7}`(cRb$I-`AOr`tyZzw=F1|VouY6 z&f$+*(T!)eSrD{)nmoLW*<}Z=I{JT{*FuJac0<0*SLT*cJZkL6I8|eUGIrxQ&V4xP zSd57Tw+@#V2(r4iRoJQM01N6ea(}|KWS&KiH&|r5`>Sy6xmGyF1h$6;0y z+DRT1k*(vBL?URA?p9;ya5)$})^f5fM&&s^%wmZ^onUGHS%c)60QtG-K4SooS4*f^#GuQif8b5w)|)C+XOFd(;fl#)~4b7Yl5H zWnsJJCjp51j8;OFEQN_JWk(}>y_+&z9A!6yj02o7>CH2ICHKsN;bg+W5P&iT_0D); zagWE-1=n{k_Kzi1B8oLnw5&00Sr~E~1B~O2Kb~oA*Ua-S1|f#%H<*(2j2z%EIT-im zo!N^{;#|b?UXL?s`Fy)=7z^*mtw|T}R4e0pyEJS;Rb?GLKh7#Exll zAcVPgZU z00{th13f)xjeN$HMB(7NoH3atVHorv5C|jGjMZy57fU~zD`s+hfa3~?cq%#&GtLfA zUU;C3nBccv@TBsCn`Ar}87BneCmjbLN`ko=JdsLKM2KgGTY%GA$;!4e0Kh#6@99xq zLu&&EwM$r$vzr@O*?z{k`A0d*5y0f04r=YR?QsB=cNTQu02^rO$l#8D8k=~!k(l9p zy!oa@P^}vD&%YV>&#h%N$(Dr~p^&?~gEVf@u!c7wn2)Ig^Q&>AO5tU@Hqpl$F<7mH zg@-#=mKe##Nc@jVuX!pPmVvSmOuuH4ILP$xgY8d=B9{h6Epi>RnFx;nlDJ<{-1p1mmUwK7e{wP0KVFC7D5nB|A5a1N5%Aq|v&UF{r z2hP>?1Jj;=8ZE(|Ne`Eu%%vo6l!YC=f$Pmyg8DU${?!c8!basG8bOo591nh{)|T2( z?>iX`5Dng0W!eY>p1nu^0IH&*@-vmMv3BM-;hILBRxz_+Ad(j+pd+W}P+p{yN?cB| z%!p%qRg^Nu2N?{!6(^8$$1FfC$f_?}LMytf&pp=?yiF9Ba~_+ll}D8! z0OX$eAJ(W8lRk6`L~<*>==YXWCmA^79^Fk@hD^1O+Tz=3B&I7lnNOA&ec{G(03eV# z>FZhSPQ_7vl1hbITMUw89PMHV$2@`0tw19)$!igrgGXy8&Sc?vCj;wAT_fI$N+zo; ztvcM9VrwXiZM9S-$31hLZ8_=edsUznBA9)KdpWm;QFP&fQZgAwI0PK?&Iqi?E+!Kp zw}MdC(McJJ-*AuB0&C30^PEuag6bd@(&}9I`dLA4t`%Y zbr4&tV}^t<1QN%w2cYkh?MZI16cV$W*x-qL*zObMEW~u__0RZJOW`=uO_E7$w~rO8 zEz~|(jitGA3^OSpfB_qo*9Rw|3^B+x8nmBk^ApN!%2Q?mV!pqpTGfT-b(lK@$!KDPkvTHTomPpQn0su)Wo_#j2r6CAMXME%|JW5C}N+=BbI9m?W{~aJyqGmd9d$ zpGv3pR{L`!%QA#kYk5`3{P269T5?Ipa~gjWHDZKK1Xk+t$Zf=UbbON{UM3KuRfq@?|X@>`>`G*+hr=E4UnlU_UBuOhV zi9iNH=)HqyoScg1lp1Ef@+9&dw|}OHCn^Ljah6t-upk0YuQ(lfro@*iACu(ACCm{v z`25fc#;5prJRE+sv#F9vZX;$YgzrvH=JZlH&pFSvT8933<@-!Fvp~>7v6A3!SkDcT z4}Jzc=zPr1b7T*38_0_bG-*F8ZkDd)j(N)rh3EU;^=`>t=H~3&;wW8$#|QVo9^~_Zk6Na(NVf7cYctG&e5jNF(hPISAZM^04tk0?W}e1S zmD)9Bo(P>{MaP#QSq3r=d;b6~YP>df(A^u0tCssc%9Tj%p)6KTak%zUc+YGfT5Zg6 zPd@u7r-m1eSgg((LPyh%eFx@x(35S7SQh22p7a)LSY#nxheE^nu)DF|w2wbI)}>@U zEbbO~E+b;NbD{{W}qO0wFAMY_D4+QSTtvn*@9 zurj$B7|H9;8SjoqCMJ-`%BySUlr&`M@TeYcB2L2x^OE*m9di4~?TUVZF!m3%vkF(oJ846Ea0DE==+KXx94;$L5 zwW)FCTOyGfw?F_q@th3PvTSizL-$)e^E<5bIxrE(9O5=qw!aGTbsl z(J+V=Xb6`BnlMThR?0(Ev{{VHu%*~v#9I;-YV*qj60;RE>!61t12zb=6 zRy&k7dIQ{d$*Phwb8DeI)(-^!WRb}fxC~W>(96^x#ClX0C(s~FiM_sNUyqPcMZ9K$0Gm`df?}^L$Vd6(HAW~%Ps!^l4pQPuz5Dp zGKm>SLI>ge>b%JtDEmUVEhL+afGVtojso&Y`EX8g&u;X@zL&|%2vr2lwnVm2;fGRR z8OIpMZ^oA5NIa?MoGZ;NY^yHf1af2z#16O_9Y^KGX5i#(nCQ2~ZtAeyC8wIqODdY-5cUNnvfI$iS}Nr2TyWs1n$$x2Nq1BFSp1%s~pz{4KXUoOLV%upF%3itHb_~ zPniT)URtPdtja;@-yWoA9r}vSUgU{)McL!ro4D*VgBrI4=wnifvZKFJT^r+-{5^c~Kq1~2^v%7bw!Ou~UN1?8${3x|g zLI~C6kjH5)#n1@LB7K}Jk}w=`oMhzmsnf~0OLUGfe4+wK@sBN7bmO=f>HZXn0!Wt< zK({K)!I37n^76doo^lUCkAA#!c_I%B!vdrZu(!!8kC}kU!yf%kD%xnvnXaO}#iVMI znO@+-GRGn`I|*aY%1_=H?mfq9vX^2>re%gDkIN4fl7-sRX9Q!^e_F+nzSjkOWt4p_GqMSzZYP+FPBn+(+{+dZ-7C5&YC&MUR{)?fmLXNiE=-Bnk@MNZ2RlD~?I}5m#9vxp$T`1bYt9@xm3bJAaKgS_8ap z6E>7WDUx`#1V6ls$YUDEgSm_6gUA2?bCdYivxOu{T^SK#jhSM>1TXj#$Kg%8wSOX8 zhPIiK5wzY%APcyjnB<;1_8fZE$Q98n)zw#gFXn7z1-RoQ*R}`cP^Aqu3!@AcSN``T*$M_Jg=DB zZ(iH8p84n8RXL^Df=T7J5=P9@Ttgq17>^$>9f%mq9;6djrG!k+nPf>MPrbhpw$Xv| zjx*|doYX2C$d2mXNMUFsQq4MVg;){GDHvrPNIiO0Mxv3DioNb64dlgXa9Z6$lC$qV zV?4+2FmZraBx3`o){=F&6HhZs3JER1k{#o6x3KOH>G;%>KpFSSOB8Uh`Cuq2=aY(MY)`mD{L)%;L*&I6CWOC}3Q82!)&dLB9Ljw%@JVsOMXtGP&qEyV5w@^X0{ z>sJ*cH3=ek?mn^dC-u_caiOnQNJKDa_K(c8xTUpDqe$TOBZgMqoQ7D`1HAE!5=icN=dUtNZjBWAjOI5j9K4og z@6AsYsK zRl}Hw`R_@3GXN34m9dqX*8>0_raDw`&d4NY3hr0`b4&7RmtjD4xEmC zO>U~_RBA~yUDTfN33Rb@3~O!=lCj*0BWXG4RFFrwH5$tjfqK!rG06-;(k5vZGvBW` z&wjY;(=^E^k~I^Af@FrleAHABs>T;;oGvgx9ea>T&P`9G^K2I8CP=|%P*^J!Jogms z%*~@Ha*|vwU0ZLK3!oAeIQhSb_w?v0Hk^+U=aDrvJJ##Lr0$3s}l&_veC3|bFtY#3(iSDuS&5H z^JIZDXB-nq3A%f*p<@JsNC1(HX9ttUI@Mh>mU4_)S)rO+$e@NiM=IhH>Z;N&VT||m zrij){Yl~N!SZ=ok1~(|c4!9tKKBAu17MC-`Z$tg6+CpukGT}}b?P3AJ_5T10X;3a* zpg3w42&8c=dMZbJ!F8YI$6=sKzaV zHfbG;o)?}5cmU_GUMY6G?JKmYki&Cs8;c%$@^O#zky6bpj*D*VxfC~@GN@L;z~uGx z{e5d%W{Nzlpn^yd;Ef^-BtAj~SjI3;2TsGKSdRK*7@uS-B>w>G_6^M5xNgVa(yX<+ z#2!XvkuVjQfrkG8>(ps$Y@66_f>2k=fnz2;r#`2F(;Rm^(wlcGQsrJ{Xah2%<~Bzs z&+^!^hRzN?hmZ4$B3Nx^mMIyP2r?O@l(xg3M?JaEJu$^v^2D(z0l~H;MG{Iv=bpnG zhhDw;>rln!IBAk5ZH`&l^Nu=?!icC4rum1+Th4oiX&IQaCjKOC-5G~HdeIl|)8}>) zE`H4dfMfD~Pxn|i0CxvGW0@4 z4tfsRJ$WEtRL#aGOdOIE?8`i5r%TD$Cit4(WmSY{B)A~%Q^?1w1D+~#wiYO(EU^5J z1~@&crs5)!<>kQysodBY#}zN0g;2};w1_jt`!LP8W0S!nfx+N%M_O=E)Q3=5ar^D^ zyl*LQEUpPsGB7(~yZ5I&YW`Dsk*;D@4YYuuAJf#Hy=pNe{{UygeUe*zj7I2HnNRmw zc^K>XRfd@ZKz1{cl@Ui7`AKZ!>Ca#AqDsbY5}UbZYY1V4vo+K=vIS#kVcQz1$@xia zk&JVW{dlbZ04>zYq!-Bwq=HKk{3EwH>sRBI3w^HPZX_t*y;$b**@v;g^r$X;+o@LS zIQ*n!0hr}SA9UbwPCA-|R3UGP5wK0oC)nF~izK<_N3j(&?-bTi!5c!RS&W8Th)GqG zfzCNNz(1ZnYA6~@i5GJfEC|e*VYi-7T9wMIYHo0?Yu2l{?=;ZjMWw-mu~=FZ7!aWs+bV-#?)3c2+-9dS~| z($5;lmJ1%@3*-*;<98&IJ+5bwK4e(KovIFTj2z^0cr^L0Uws?b@PU{{Xy^WHGMMw3Q^cV~(TWo;al3Y$&Ns?n7d;TqMRa?FzvoGsBh& z2ORX^la76BM234ySqp6t+qPA57&bWL9sdB&TBB%-l(PFu#P)ErEzQzwX@JQ2f{nY5 zbB+do3c2>5D}0+VBeZ*gJ3}Y~r__Hs3k=S<0$A3{t3}??J-*#bD*nqOJQ=Ik3C%CAVH}W3l zO}6{zWsVkbJjEF#{c+HH`qqgURn=@zOSz{GU?wzGZ#d5pUzBoolfmO0k8$l+q-o*u zq>a4RU;;)@-3PxxxfqPezh@@60XuMu?Z3?uyCx+ocs3Uk4lF58X~jD zCcxJJ0KIg*+aL!c8%Hdp1_bo{>lJ(KZKzp!Zyd#LZOpM1{{V@7!nc_+=beNC0|E1V z-`zOtQ{5u{o6U?!13PbyLJ3ySII77F`Iqf$5RNsCiSi1E&UnB+qq#kYtyz`rWM#59 z49g^I{*cXvSL?a4)E`0KqEeJ>b2-V#$G{R8pgu_c258FwJ8&`jRoo4RMG?GAgUkYT zNeJtJ4?Vj70F6A#(Wyfs%BrR{m6V??eYo}KiiM)JOH|yGJ>0SX0In(*3{Pxlf(N%J z+nu3OOt?O4jz?fvyhH^?@*|5SSGf1$tTMEA(S(`{iSBJTA0feIjN}l*sy0F3{YM8R z@?=JZkVeotozgSyZ_63S{{UOAYOGSKB&bp2WhcvE-#0vS?bnLZQg$?oOqN*XW`fw< zTP3kb%#x^PWIYKu2ZQaC!KcG4F`_I6MY(OUw##oWIMfVw_8(Gt^))Nn`KXbX5v(Yz z%;yBJP*1mBwLRoh*n(veA~9Jejcx>sBNh36Uc>@q8&lS$3W@#ewM!`H}g=qGI#BxZ$ zIRdRm6v1uYU9lJgMjP*L%MVVSD=E`$mrZDBn48YHhHHF6*6aJZ2?rfP$GGl2s;gXC zqO2@DkhtLi;e9eW6ziB@Y=I|@Roy^lVn}Y}=RJ5l z^sMRGKO;wEwH_meS!Q&T%!yfDB6lQi?0NU~r(Brr!mBVbF%0*Qoyy0aY84F++2oWU zwum!%k&FgCfgFCdVkZRMNhn6P-y24tbYOV)HPWP;IVDkZ4_mn;c?Hjwa9T!bpxn+| z@+Td6;+i+x%>}%3!)l=Jj$7MdByq1_m=JO~=|s)vs}V9_NUFO)3cwh!OIK~J({{Z#s$%QT@isY>AaO_)bsJ>ieXN|waz4`8a0Hzrl-Z3<`%QVj0 zP%I%s9Q4QQQ7VZt=Ln>TqD)*zCzz=jJX~BxR4V-jeS1|_@)l5TWb*DFIY%opK~XZbYw|mQp7ISKuazG2dCkY=xXCp zTE;}cwW7}yjHX+JV+ab_jCaBGIUf8{tXEeM{Ob%W95J*K37Lx?{e}-D{V4;98E+-H zgUU#Xh`>9Qk6iX3jxaqBsHm=w+CnPH9Gjc>HmZ!O6byn!F@x-TP})Y&npV_&sHKY-b^nmvMgntfZ6~Zzbb8;1~QZTw(Gz>#AnkJFF zt(XN#9s8a+!S(vqj3h@T$|E+{RphSajxcz~Tz2N6-rsDEW^$PaVt@k3*z5Jjr>%BV z&~kFH)j*?cae*vYD(<*FdXY^=y5I9gBQl2b+i2Q(Jn`Qj=Zd!!f(zIfHr0G@NnFef zhlA8|Gwa(PnWn~*MrMLYq-Y@xvQ~9IVw1)(&OrJON1>{7>~YF(n4BZ*jrNHcCNbkOv(x$0I+O{Az40O46;+x`q@Cs|hRRvFfeB&N&!7 zXOYsM6nie@x0do4BAvGhB*_tupwC0}sP|7NO}QOGZ2NSj zLl7%#wpB=Wvq;E5Zk;#;{Y5MbX=-;}{ifzNC1AL=Oo1kN+zts-(4N`J;2N=dQTF|? z$g)JiVrbN`3fbTh$N=-{%~Y=x5?tiT9CnK=s^Pa1#5)1U_|$kA<5dr4+?+{SA{ zk)(0-T&cnI1cT2UP?lJfmkTTc1rcS5%LC6}trA$H;z-lTX*0ez82TE|aeFuw-z@2O zC=$KEZMNY^D!qyN?Z@X@QL$)Z^V@HbSII}f3ZHvw=b*_yneUp9?DJetws#E`yhNj> zByGbu^aV-(04AdiEbOoaXT`ej4mV-4M_*q50G}05+{=~Rmga5cW)B^@U^B-a7&kou zZhf;+Nj;;HaSWl9$S{%Q$Q!;%;~lU%b4|LnZzV~)25@pP zd)EEclu$(3U@jQ0)?b(~&QCf01!CmxQnDepGLRiiEU*pH!1{8^vqpN7arasloMJw5BPoJTo#kr}QqL1@7FK;!=auUx(22&WM&^3QIn$1_ADVe9}T zcc%1?!o7}O+F2#JSs?jQRd+_`YJxc986M-MY0O&TW1q{BV7QP)71)q%GIs!HB!PlX zILP%CB1aQW(5jNsKGN@j9^4X1Kc)ptnq={!TdN{W4(M&x61!u-Aods_@s7QERxRA; zo~`Ipwt`5fk>B^*Q)?FE1F1jf(yx7*AhK>QVwyl+G?2#F>C{wk3FMYWmLnKDgn+m| zHhTRJ^{vRFX0>aX=eH9pBXa;gQ;cAYV<+?LP^{T1m6^%MVLLlV6ta2zd2A6# zRUD8rn%=OsG7z(gLqw-7lDThudiqm*yOma%`0oG2DMqRxOOPB+5?` z+Z1+Dw>x@co)1n%YfqUQMlrcoODGm-Vzx(Bh#nb>E;;q>&09+=*lupotx;A86{EQO zU~FPHPrz7HDQN zn9Rp(YzQ)1LHcu^{*>UY663E@v?~;Gd2IgxyhT-vxE{TKI@xHYF*)Fj(V_iG3K*d%NMqou`e$x z3l$j8%5ljAbjbCrbEn$d%nN?k;-3j#zHh9-!nRqIpnTNN2 z)tTX|Lu+|7kgBYWx83eH) z{G^K7@jjPvcc$FO0|t4ZWnxz+z~;IzxM;=mSk73ES*O_eN5r2DCi`?PZx5R>m~Ke6l~Oo7jtH*E zcn?ssjtC^QSgsdp{P|XFjE<+CIn8}x7K3jr^W3U|8nFo)LIi8c%Mv^E0AttMtv-tq z`BxG!Q@3b~>?tz2Ju=KPFnGxAoc6AKMn^{zHz_?C?APKtxT+DR;M?9VEDl z0p;%bVL-lEB$5H^jN^}L+d4*@Dn`&n7>_@@DlzTt`5JU`g+?}s=2pc*cDcaYyc#!^ z62@*8WyIi+uAukG#twQPuWZ%JHq|bbLWL}hS~OE;q&VCIHHe^0@VUQBk+B<(LloEJ8oc{n?tEZqfVF}&$PdGby;+Ys^MGb)M z%lyRi-2rczfB(5VnCtAI`jjXnC~`qWr&FtZS-#Bez${Qm$d zomEhSh0kU^ap_FkxbS!#Nni8%)IEz$TzUD5oDxyE+SvU4ev}`)%z02cdJ+CbLAd#f zs~H6VRV8=}-}zF=$}p_zgp;%}<-LV#88$&$;^yF#OL!5>ANgq^Uzfi?e=0>XG-(`| zV(Kt>=bm%Zngnbm0I6K5=RJOu_>cz}Cv`6zx{F2 zry*u-+rsAu0F?!?)cWJ!+MzbV>T^2ENbxj@u_Q@b$tb4A4&#YY|M zlhr;~SA~dYX53hksyg@nLYr+OT&yLWGKPTgsUQwCBq?H zj32IjDx6nH1AxwZ>a!9P*!-_sQomr^uqF69s$>LXdJd+z zmU1;PW=SMcL)C3ABqlt~*TF`yC2EP=Q2*!KK?TJDc3 z!_|IK?_PJ|%h;0E5=eqa&zgcft2TOr^uWl+^RA%k%jX!Bsbz^uMx(At1n2PJeQ80o z$*C76T+}8umeSm!8CocbNEC%SJ*!NJT38Zq-atY5hdhs_di`qWWdj)5 zNa^ga{O5IG>fnutBW7$9!Q(u4=e1naq%Y*60Ow{&+6dk6{{YvoJ<~OLe%W<-Z8}@| zF=SgPKfP8MDu);t!28Gbt*d=wYdZp{WPjc6UCJBj-nq27x<@~&T{WvRk+%*DD&z({ z{{T$a2duM+XPm_=ZB=Q=R>H<{u={6l=e|d^bbckgGeT{nx%txM8BdbAW#=b;cs(!x z$0YrH{_bL3&hg|%qY@K=yN*w;C`~))6yV&oIh&V~BjyPH{*84^HFge*dd!e2L}Xt z`e*4~xLQ)Aa7s#S?5<*h0UldoKbQWI%PtghGxYv-&g&5A(X^AQyGaae%qEeTbjij^ z+uHzf`C^E?LmZLC9ECCVeZ)5^t&%-+#sU0moV&Wd)c)SKk`g9sWJ2(>F=HbVNf{@OdmaGbRjadb2IX8y z5MYGA1OEWm{cDZYFE4Fvq_vF=&z&OqE&~!66O|uL-93e87TMcN-Yi_|Y%k+vkU{|w zm0y%TbJ%g5RW#LLi%|XWR9yb!X**bhoS*);psqRYhM}W~7gUZ_a8ZQt1yhv3+l~n1p1phbHOGjY)6ng7`PRq0>7FQxDB1;JUQ2)?P(u<< zPCdD+X?)VWhB*~yj%>0K@~Ixay=%j?tx=lmPl_f)nhTj$c+5nZ9|Iim)2|-&>lSmQ z(#auTA&g7+n1x_E)M3{=jtbNr33FJ|m|euP86{N`&$62A88@VQvbYvy6D;3||f&Mke-)b%&`zq>xu*C4QETYIwEKJLd=WZF4^$Xjc zq@4OGGO1M1+_=4&?j(_Amut#==U2!iXCuF%ADvdXg6`NE;}OU%3+^i_g)8aF7{}|H z^ZQ*=SZu|sUfy5NZzkB~n%!fPWydbzKnlnEpktF=wwpEG-IUjN$sklBOPNZO$>B-u z&jTi--nlg@Xf_FEwRwavgBnJqCPH__PXuGSob~m`tyH=31U9g2xM|iX!B&#i+|0&9 z_i&>b$siNhbK08Erp3G9WcNVpF@MqWX-C~td>Z{^9r=nNt2)U zdE^j!pROxT_QG)%#=MqGsnw*)x{W8qvPR18AYie4!U;Uc%$*Joa6ivl<|MF! z6^@XDt5VdI z_1N~5)qLx1)~r0~qLE60!xks?1CB9SHghM4%O#&9w!zT zDQh&6a~p069_A7Ndk<4ym*MXb>GC+ZzzsAXI>@~_;{c91{A*ZLRVo!J>9Fq+THX~3 z7DAKSv575Y1`FQ-h7e_s7-*|i-; z(c_h3F}uESgT8&owRx7O0!;_nBuhx$#!6gHU~{Yh}Dr09QMslX(hp#yfI7E0)wVV{jfhlWNW7v?|_b zBdJon5P2YGxA(5Aq+GJh?+J7EX{JFOj5CF1izjP(jPdKHrIY0vZiG% zPh6ECjw^^EkOsJa^mmbi6;azGjPpr7wal@_363c~&gH()COK6D0To6Rf=MK{dJJQ! z;o#L`f$dfI?206nNKL8%&mV`Sb+BsfGfU<$f*&zNGNe9RG-s9E4o4${kFR>^oVk|7 zDpE#kIa$&>>#1XmNU^|et;0te5AS8{x;4Z2}u$Fas3V;_cdS}%7iA~`K9Gj3QoP`xk*ujB99xm`Z(H^&iZ zkub#XUQT*dnJOE^gElhFEDi)GfR%8+r zw8+P+9!dItg=neBIXRA*E(6@Y8a5XV8tqpc5D(4y`cC-s}zqs_RIPB8kt;V5k9ojQ|w(^i;TyvfXIR_ZURgsI) zn$b9tDA3x+1Fr8ikhjc9C-{jSz~cjo%Ds|Xdr2alqY*hI8%u4{ES`kq76jmS$0xm6 zD$~lF35Av=WVeVGjX>@0IRc$~Z>yN^!3u$6EC8w718(A4`=6$idMtJ~^fb+-%jQ8fQFkmHgC>&%+UPe{NU;rHV z>-}o&^`DjJM(HBYGOGc!i~<1%9)uj{(E3%zO&h5s+9FvcOHl$WZwkW7tdW4iM)f>o zboz5stTJ06vtw=#*<%pJX*y2JA#QgSBy-t%)Hb%JNZQ>zu{@49EzGK*uo?Tuk5VeU z)-k}6Mzi@+%_^C#)0Jk%0T}C#TG7>aCh)kkCCg3a$8jUZ+i`Bqm5sfC9Xs>tYTOEK zKGc`OSZ0;}SCRISz{ei{0EcSLSfz9U-e{#ekVzY0GLE<-oPpeW)Uz*`_U@pxZhlxL za>YsYEt8M0OjJ1sG+Nx3?J8rG$1Ak4$f6~b23@_$%JllxIhBE))^X_t# zo-lfJ&!#%ogfP0!Vw>#iAtTIqZWcu#bOUb#zduS+s*^~^lW`yq=BafDu^#mbNNJ)I z406v97f50V%@d{>v(bSgp1qI%0A8SIirR={w|J0XLWlrfKiM5PrIDweK=^R+s_wp* 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ξ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

T|#y5~Na^r@7S*x{Wvn;j%k!@Amc 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�{1CQZ@jc0)I*2Op1q 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 z zrgM|!BIK!lKm+kKqSU?_aC z-2B6*6*V8cP4y|Pu-ndlX_fqy#BUfsA>^F)=LBQ1>+7j$db3*xjwo(A?!7Y+B8|f+ zx#0HBeFv>!-N|My9_fn>MFW#zw8h#PUZdWP4c7GZwdY_TEJY~?_ zhTxb~$9jr+Ga-K|9dXQZ zoNaEP@z>WsPg;C-vD{`^cchWO%`3j;U_aUIgX>RwWR5B2LT3?5q#!b&Xmk8QNTDmQnf-txYUITeZTn>|)!Kqb@oV$A7QkSnUxC?`?e~Zi=#Pf+b}r zdZ8zg&m0ctnj^cKR*)o(8Uuo(wefDHp)WW#R)lSHsy1iusw1zIQF3umB}X5BYCA0 zTgh$})u2Kb_mLCB;Aa5vK=dN9Zl+lzX(KZTSeXKEE0rMaEWC5cz&$fc8dxUTE+0Hc zBIE$M>G@V<#nNXH##SjeD~5cHz?|dtIIC7ni6p`2K3B?QX9R32rJKG0A6#^-o9TC~ zPEhQ*1AFtjGt;2;JoCuo-lo2}jK>6Of)|%}%5bbkI5_Krf`1yKWf9J>F$@~rOidnk zl6vPnWMK!E4O0i1L5=Ja`L>LxcMsh|u$2|Qj7V1lBCpP=RyC|%&tBt{WWUp+HY7T~% zV+U6Az=~9X*xM_4iUA&2$ip%8JplI=Mp)xWVU}BiZm~(`PX7QY3^{K7yJS|C+7srZ zhjAw6SeNA_0k;_ad8|OH#9PRbkkPX#J5_{h^AM!;CmjbTpvk1SGQOp;J;m(U1I`x= zR!#Ail0|NE4stWW&ws|TH5Ili=4RqU2$SrvEz`uR#1ZptKQJA3o-zh%878=nWtP%6 zXITq1iFrBb zc+PNZC1+cd`#r)0hFr1S2H-RO?yJyoR$xmjRu=Kvyi5_k&jquENX8D{4ofaL1L%Eg zM5A(VbACIUgpx#-;qD!kSIjf+5rT8T9Xs^?yzAOr%0U~Eh$XPh1~J$F0M%UWvk3*l zeV7R(jx!@FVTk}>{v#ayJ!-@v@u#^8yMw6M?Q&j6C+`*{WF6V#o-xlfr6EoUt&Wa+ zi37W=W__i$a(6Um9Ff@PwolfsrRue)g)t6C2i&g zNf}OfEHE2AJ8(1Js%l!CqUw8znn~^_E9YFhmUnV;S-9k$a(@~jCnKL&vu10<6lp7b z=W_hWNiCmm$NKiHWYpPY?ju%* z?CU1kFeGMEf=)j!aBI)(uY!5eF)$AxDmp6`X3ta4zBtE0?_C>Q5d!_A?GY4qXksik zF&Wz29ASnC_8^g-Di*BTl$oOUGI^3PjO|2?8WKvVRp{9D6xr?rxmbLsx|`-{RFm@& zoVI(8oPYJ}pSiesgisMIPY`CfzVk5~XBbdAJf5;|(mt6)O3` zB+q;;Y3%iS3urOw~D#e)f2O#i9LH0Bj>Bqh7I%VGj7Z}JK_Kz{Nc68Y)FQdEkfy-UPb+z)X8G`Y0gPbeYdvh|u z0C^?E(#N_;7En*##z^NG!R!31i`L||NIdVdq)w6sjzm0@lh>Se!NDD?mZM3%PRc2^ zk2lsd%iC!oxW3VEw3v|@k#AxM*9r&9!)YLf3;j%&?z+j%aM8v-%*gS8!)?NuW@ z5Ad&H)Ix6%$9v@)fErPB8hAhe?reVv8@K>;&3TrmXJE!p?HOHG2@1h1P_&Fe^ypL; z#z@Z<=hmE>J?ag{$Ilw&wWWlNVNo>DWq)%X*kdE78P7lmPNum>oH|83vwx)qUojp( zln&p*LE^n%#7l0*Yj`7!TieL9JZykSWN-&B)qx9;4+D}ql6XyV8brC7rrmPK%p%|r z^GL&Y1ob?UNjTv8S1fHK(Dv3m_fV24qr9<8scod1)TDFcY=xgE2pb0>MtgCNaBC9c ze>T`?_A;!YP&3^!g>9?OeUBY8$^0vROBvB-wU}ClxSBZ<%kq%O0RSrT(>saD71mh*w3;KT(d-Ibf3FIWDKS-G;{E zfw=j3+I#1MK=iG@2l$%W_g8Cau3*!kfv{w_W>u578$mf7pYw{~BL?-t+uQ0APxkGB z1*@ZOAc3@FEHUZapGvhI)Eas)fn)PwlpA$)JKM1YV;y-Q`c~a7-PB=N}4t*=5bXcOE;i8T?xsKu> zmkEV0Qc=ny*>kBK`EF~*#A>=HIaj}QWao49qUYj1HWqE6BAh=kr?k;4G7=dLB z0`=zsfdui-L!Oni;<=BH#HrDit3r;Tlfyf~$CPagD>hpmhx*qx*OwM|N|usCb*Fi2 zB+uj)X(ViAL1hdG&N0B_jEd{8tzXHyOwIO-cUZjC#w1b5!0CgW5BMI9=IXjOQo%^MvrpMCVdd=ydvQ(A&CQ+RHtZl9z_&(cFLDCOB!AvGBn`s{1Jnw}l_a#XR+Bf5_l(kBO)&Eq zvC3gbIQzt~I2;UfR&1|N+9XLy-0`>W(VHy3r_+;$6zw7az;rx&TuhP>e?NfX~Ne}uxTzXWONO6$(lmTKJUDsoR;_h z0QL8(6KL0(jn17elRVnQvPdL?D_Dyxc;{va$-y|m@0?^*%X1@wFP=R*+B3Fk=3o(6 zaC&s>&(@#2bt{@m5m1ep-r9)Zwz`Rh?6PJz^R5u8fN{{{mBtQzO?648TC%`Wc8$Ev z%3?su%roCTxE=b}4`*^N?W4AxP0UuIqmBe1i4+5Yl0YE#?dx6Dj5cw-l3TCY(I6^g zjXqU7eo>A%?ZtIL-1Fs8#(S8$loLkEu}k)pySYJ)M=dpDpuUT6xCg zd2<;s6s~szk^$s$4|V+fD@@d7ki6P@#UntwB8p39hTsx%PIHcU9jK7TzGmq<3~kOqIOnE5l#$(A#>RLSHJ8o;WReAF*RB9wK^*t) zdU0D8a@$zjNpCf!r|iSBxNNUOn-! zbLL4DaeHtk}TfITe^Bk`-2r9m72H?~2z)=nXite!=2G^KUXClq#m&9lzf0KPv0( z8W7*Ql1W$1-Gw-e5HXGh2?!~Xaoh}cJpF4(?#oj5PRmEU5wQk%)!H^8t`%8|p2K%SJ$}Bm+3EVEYO%zu zb0B4oNf;1i1CTw3TvwB<(;xMs1Zj{QLo&(%&T*cjr`MY3>~3Q*#8px$iyz#dl#hCe z%aw^mxgMkavi7#_k?h}cL~`wKn{ebGL7tp?S2s4kf>wp5i9DwHq>;AnIr`(LHO1=P zT1Uykx1b;6T>@RK*$&2Qe>GiZ4UM=Qs`MV@kb7X`HRUilK57VL4$_Wh$SaPcgN}Og zKdp6^6Pcq?5hy&pu5*US&JH?rM>=M5qME&rQMbCcFha|3<}jFSi9jsJ2aI>mp{#q@ zB)I!ba0Xzg?Com-!Q8w8xCev5Ju{QgiiX{zh9}!2yq;q0P~58#+thXc06bCluPS-n zu_%@{ZIY5O#AC4sAe{Yut9aG2)aK;nk>(dsiJC#=y1l8xG_jBiXFo1SIL}f1!K|f~ zU8Gb{QAqi^WS+vk4)P0&*r75qm5p0Fj@4BJk^w!vz0a+A?x^Uuim(=r(izX282K5L z`Zf<3=tgn%u4;)&SMGGePHaihLgj=^yEX}-j20OqyQRD6w+ zcCS2)bDlXriMEhQAdTlcVvw*qNdr0H@y}1^ROPg~XsBSuKdXPM~F=52>qj%>=g2B91uac=t-OxKMG+ej}U? z{0{Xj7ShfdW^)rVjEQi}Sa-)AeLj^!0B2>92r9 zm^YXrM9ieAAyn`_fD$?BR%akuxsG7$Q2g$90K?jAH6+HjE!AghmYlR| zo=6NA83T?mdJm;I&ghD>y4cQ*Wx^O(MG1|X>1JKZ(UZp~qYQo^`|uZ7Z{oIPpA*5l z0~7^=V+WErT<47T=~m@*mN?3SV7LZ3VvL1l^lwjYIj6#g+Vqy<-axzOY>=ur$;NSt zOwKErls81MwY=7G?uT>DD+7k)o^pLKGCe43h~~I~Lj8zbTd9p8&e)2do91kdtS|sP z<3EM#o1qkJ<~Us>a>e5tm9fS%ft>sLRcURcNTO+0>fPQYX$1CVBT>~#4E)MesoXtC z#}t;VB^MF*32yKnSs+Q&?uE+kUU=aCl}=-)mT4@lZv~i`wYuKQWSM@XfsT0q^x$@@ z4@HnY_CzqGmQ12WV~kkYswlKOFhC*C}xsVoH1PFo?Daa z@5!;xX5>W}m6XZ@E^e83oVUx@>CaEXmg!zAP_sM8B|csN#2c~$>CkLO_ zs9eo(vm}s&?_T z7ZHfqyRtCyj{$u^@7NxFYW2i-GD9Rb$oCICk&$l#oS#~+Yj+pg6=gEGM*jdwj@iP<$aBXa^%(@< z_w}ivwV5Q6c-q(qfLWggMPY(-gWsHFdVV#e_K*vgoI~Wo5q!e#H}1zLj9?zVz=7{t z^Jr=9Rf@M^H~pSn(LVKJ2|GeJ-Q)A;y)C>-#zpeBhlD91N$z>}&s^4%2&9ob&AVp6 z5*|XI)~L;OA{9tgnZ%$zaq_6(S3f&%%un7$WU`(T!ZJ5Zg&i6o*(atm&UorQed|6i zoJNl!j!ER(xZ`Ns{xz>NB2I9+#LM9LG{H`FvB5^;%(7K=C_sd z=jm3In-pT%B#_#*t3wx>*Kkf6W|CEC+CSmK z*B6TynYAN~PReIlSg}sOFgOE}M;YiUx!F#m)RI_CCK)7OIw_Cup)#~=GuM&GARfM= znuguv+c0GfH{Q-ducyMF_FTB6efI4=4ef2dN#8u&oQ* z8CF6(=;4#g4ogH^a~_??vCUI^dt^Upo-4zNV<@i6Bw@OIp+F!88?xEPdf;%rBeE?E zYLZ4@$!;*r!bACw)1mdKPG=ry&Pe$~f(ZJ9{HkSDUoc!weEH;ejI&^|>&eeta0NEq zJjM;UsgMn%=N+?7&FSN8trM6ZVi$F?s|03H6TTGx)L~!Sn#O45xdl5vGz5i z35;BAfuxRE6B&~Vpkt^10I$}YaS{u5*kVZ{nNn@&Nq_f9TK8YWB<#VXRL@UQ&)2PG&mmoq`RF{$jqe<&qZrG4)dJp4c9W~Ib!@qL z7oDU0=A~PticPMbVJaB$l~7OWDg}^7xl+^{d0C@~mj@(re=k8-7TBjdA}H1}CY%Yb z;sCHR+KA*-$l!IrBo4jm)M}|9SqGR^42=#5D;eldvF$@Ts)i0(T(;nf2vxx2{Qm%2 zsT)rf%!b@4X*TaH<>Gh!=Ln%--e<5lup@3y$P`I&l>3I0RcqmDOe zB4|L|tj*-|Rl4m1+>-}pc z+1i`Xm5aMeb0jgz8(RgC6%C$q#(4*}M{i?Uk8kF*cONW6%y0BH$-?&Qo<65Fa`sz< zD7LBQ#~f%fN6M^vllc07_36+%Na9&xjR%%;n~vO(*q&-#+742@i-|*vPqNzi#yBF2 zEf{6&q>>212frBgrL|X$np_d~YnBo&;tP5oOdS4|W=Bsn+Qdw(xNnsX-azO`8OKgL z=7AErkC9e5-F)eCOEYJJ!`GnW(0bBtDtRsWq%qi!_WPiMHF!zaVuO+ULzXgC2N2aqc=)SCcVe z=eFcxs~FjYEC(aDNT?xIX%ayvnf7@JNZ^oSKsdlWgV&7l$I`CLXC>4UND2@ggwgCc zjeD`j7&*rthKOCrsVxd$W-~`5ib(^PjWduvc*?;G|cQIUYf@ zC@hQer~r4z z5C=Z_s2q8vLR~7pM)*(y;0}4nBMsAzcs|vtifHDk8KtpM#cvC;D@hXC+mUnTpj1FQ zV1hwixH;qL$2vs88{#Z}hW$05HSp>^oG6A%f0mWDz>eG=DY1G2B!5MhF=>$llG06dum>$WF zK^=E`1Dcz*cG5|rad8ZRQVRliV4m2)ALr7dOF&eW z$6H%X9m>zVHLM7HxYc%zq!L2^0C$s~^=YM6nf%CtH;`I3b_@O-{{T98l2IN7w6IHQ z8p$kk$O_3D5CZ@Q$_eM6YNtKLrQC$iaTIf)ZPvprByr?nv5ajeJm)-g?^vW$gRp`{ zXofek;V!8xM7^Crdwm~19s&g^cd%% z?ewSJU93VqvaTjYQ4`=D{E|KR8T=|MHA5V1va3X0mvG4{RN&`~WFJavn0(oM*_JqY zSMzhXCym$xJbQZ4ymUGsrEN)t+y+>nkLI{AmL5_9$^hWEOaez!=xZ)^nf&RkrM63% zrW=Z}k~NSFb|WAjD_$3ZOLjKWtctl%@!)Vq2+jc`j)&Cx)@(M51aimZ!y88b0J_7S zyLuj-z$Agwip?g_rwFLBINZy%pD~h2P{3dT$KZaoeairX;(4UA-iAv!$XNWv&K&T5 zVaNxbr`DMqameWskjoBaBq+)P0LjJ)83P&5B;&0*b%aEzBFeAku?-u7uB31P#zDwD z`;U6sF-j*Kn~7pCDnKJp_=(w>rjW@Yb~xnlPBKqC3{^HsZKS=4l}xx@u1MMe9G`!} zq75avDvCwijtsIp5};${C4a7Y{3z5C?s%t0aIZb7Q8a8o+uY~;D>kIfRY^36Y>1L+ z7EmM}Ne#a|9&mZ|;PF}xmdaIPjtg>9MG{5`l5T$c^MG)1^7;<^ns(@ac?Dt`)!DzY{Sn=^qF4}KY@oX+TeXoGrNCy#T<~(F5$(t0PDqkq@;Zpw zLY53jU=L0`{{YWQs-?WS65JOmvIyjKC5r=wEW?g{IQHqnf{R+5@|P6(&Q1p5hjEU`#m z0Z{=~jDL9c?ZE3%Ov(3!#BfBY%;nsws*brmvFrZ;>!d*=+#j-sWGf#Ce8SRWoE&lq z=si7Xjaagw7MT^*z-d8>;74#S8DxdBHjiJ+`qrF`^0X0&3Q85Xx-N6;ochxr$yYON ziDlS)<_b3tO#AlctE5*D2+h3hF=zRulx{fp?O9Zsn=Ve}sAL8(u2o(@!YJl!Ga$(% z=b`I?^rk~JK6-zy#BQvcqXA@(oQ&rngN~!UHe?dRBsm{w0hv#AJ@Nh&kbSP{#3Buf znONKmh90#X#&Uy9y3qwbTQfxyfWSA(26_Jg>;5%Zmn|D)G$9#T)ba@F_)uiFW3;B& zmPr*-B7RT_81>?oDHo9(WW&zscpx@U9sd9m{OYfELri88YkWwmWib~kJc_G;I315} zzV#KhB`_JHjSueDTYGtlK)Lz8Vl(VAJJaqhEX~ThNpCE$pfRxj!PG64&_C!F%f(-lf(dEKnpU|23(#`7D$Cg3nq zK#h1TtTUEgR|D3o;yV-6iML+BiiO0BD-W3DE_eivP#j9lCyQ8RBN zj&gYX{{RoIR})7Y!xYv_Yaf)VVut2dD<>myY~=MGgN);?S!vce1eWlv)H1K{Wl38( z9Ah0lbKi>UinLLrrE&{Yit1ULW7XAqhSg>N-&Io24^T&E?-K&L@VV=!E2_&$ABQl-|>J;(QwImWpE6X`};#H8cyPx@E zj`_wp&mT`(eD{B5c#=OWa}C*efn4!|M;ZSB^;S*EbqJ*T8bO2Go0+E~LdwEYgn5i| zc7x7X3=^I{wV&pbbr6Q&#U!PE(HyaY04EAa9QyvWt>w=g(Muy0l3}t%C0R~51D=HU z?MvqUmvAW@uB;VVpE<}poDgykZ>MUtS*^{ZWzesF8fR<~u*kf|q_J+CpH4r{YN{sb zE>Wh4!xVhm%nLId`t%Q37PDvtW>_4{$j+^!BM>NaFJ@nn1E$ z6%sQuZAid8i*6-Eab~Pkx8#&uX$IStEs`R7uosi67=& z!?6eN4!j!49Meg%wZ7RUFd33VC9=B49ITstaBxTCQ(T6GNYPG_EYNOAt{Z5NXvrr% zG3a@ztz1EAw5qg`%Krd1z|PEijooqR3BaNlnf#$U$uW_)G*U9Ogba>$@CiKQ9S=%U zNf`3Dl+D_Sngbb>?O!@s&=!%8IS1-9k;gSOjV-*UTXtuOW?wfc!9JdZQo|TTXLIDV zmn|8dMJ?s8W^JIHdoEA6N|xR+J%Y_O%mVS}b^9E9gY8}w$j00^AYhZh$Q))lRmAE^ zA&TnHb8{vlRfBr_c2XwRm5{{Z^f?B?PK?vZ7A3Yg3| zR4eyaDmpUbCp~)isbv$pNgBc=@>epu45*Bpb?wg_()M>8CfQN$iAhB3vQ!~r81oc! zjQppjYfvl1@U*iijpGbXcq#$w>CdnAs7wM&fTHGWczm+6p;hwRJ$b=yIsE?sDmskX zZS?yHcrIxt-8&Z^A;tPx=M#7mAdkC{{Ys_ zO#*LgsM({9;|$2+5UNygyaUM#jGi)bdYYpOJVePkjTK>tPqIaL;|IR%bja#4T57Uf zTuB6p6}yPb0MoA4Rmndwz&XbNa(Ko`#WtmLIrAc&^g4W#MmEH6;$7$_$zVG-ZloM{ z;+<3RE|E=IyA!OG!ZV@ZQ>F)na*1LSRW`iKHXU-0Ct%E7Wx8X>DFm z;oPk8%8kPvs?0$iqbK}1<21mI(z>mvVBjyE2Ho3wbNs2COZHe9XN1E)5d;dpR@2Ej z&Ts6JRb{mYFh>m6Q z2~#2xPC3ZV4m~*OP%MGxo@5W0@>K$XwS5$x2=_kx@m88$!5vkk2+FE<1(0NQI6W{s zWM}JBQX-0)dku`j(<2diCde6N;6|~wbC6DVE-}*_oOY`Y`xOebk~=XiEA=DavE=^% zoYg?&7?`G2xRpUacfJokwCP?*E#5RS-N=l}W876jlgS6Z&~h=sKE}Cyoy+BHyAFs0Zg$Ga z=iAP%frG)Gori8mPr|w*bWgJK87y!Z(4<#S9mv`~&nQ)o-2FOnTCT_y;>eD9*}R~i zDZ$SJuVYy=Ze8(5alIp!IU`XK+ZVayZUEUMcA@Yl)*XG?GgivX&)TSDX?m zrNq+ABL-%SGMqY`D=5f0_v^u_&BQXZ3wY8=1R+-HShmfxJoF?D*c=@69Vq4IW=TqN zCyo5nj&Cwsi4_j$V~Flq3E%TPNSh7^;tC78gn>T#TUdJ3K)HJJ>Ll`6QIN$2@el9XB7?6lllr?!CXmS{;(aSV!g zM#GSK7%F{1Jq~)+Mz~v8F_b6T!W#KkzhindnUQ2AsqnpKf}+_NgN1deiW4sbhk9069REfm3waY9M| z0FR4B5;V)4eEj^a#@v5&1Ky%lmP24r;4mU>oRx0i6W8(YQ9~LDC4k;s$alApS`ZYB z^=x!KI2>|)t0#8uIVRo9EVj~?^Cy5vs;u^mG$sNyO)`z!SeOB5zH%Tm(tal8u>|Qzi&lPD@Kx9!09I!0T3bKRWr!^PTVl-kMjj+X*(&GuvEB$@|->cB-md1Ltu*kjpBI?kS~hTYo~HwxkTP%$Xzr5KnL<|!XofFD`%p}Gu#O@|M;OjN zy=mgqNQO&!nS_X>M>6gCKso9G&N>eN0F6HrTgNKB#7L|^c#)7WRB%shbn(1{ z&f6SvNX$&dj^a4u(>=RVvm8@Q)Pm!E+^8Uu)pI68V5>5WWR=Ju^#JpZ+*A@mlVxLX z-AISbmMrdKeZ~kr^pZ@zR4T71knP@95>MaN5>&;bJCsHiu zS>s-!bd5&*5$qc|1WnwXoppZvnT1Kp*jG(zmA!x$OwRZVVs;U&0W-Z760IsY+W`^L; zsOnwySl3%iiOLeyp58W6PfWExvB!8auzcV4xXDDJ^FjpPV+NXMUy_AAd%iB1spBB%+0x1o`X0U zJn`r~D?84XHZH9j`Oe4ZLRna2lk9(?^{rC{n#U_4M zt$7Q`*NmVm!i(gQhGM53M_y}*rxtAqMn4h+o_qP({I~>$727OODn_cmDB(sjNaXb= zuO!vkMZ2`oU0p{Dgis5q+8Bj^@e?Ux{94I$1yDvnDT8+?y63`A~7y~B*uN5}TnoveV-p!y4$%C`wS5?I z`1hh~C6?V}iZ+B9BUaphhbK54X;I}yFAOofK4O^UGGao!@K--BdEnOG-F6(P#t|XB zv{aVp#wDIO$L^FLn{IP}3Bb>$a5$?|v{A|ljU`fh6A@Ahu7HDu=$QH%TF`g+dD=Y-wM(x z1hinbdXJRgcRsZehbz>m#z;hwBN3A$lvM(CXg~{&c=Z^^KU%dSPZV&hh+(wmNamRd zR#B6M`gP``^Vyb1HqghA!3=I)Lk^>!?3hDdyb$p%}Zm>{Q9)+~D%v7?nZ?1$Jx4Wi0Hm2E)V98z68j3mZK4Z&VW_UT$~>S048 z{KYo22Ev8+??iDTn}v~HM@0G9At8tvdtp0*-pyfK{7;cQ6nK%-Wg>Bj&exrk>~|k5g)aTGEe4~c-B@Cg~wm1z&Ib{O|oZ> z^7nk^HI_26!}fUOQn>^W%nK>t450@Ej)c@R;Tvmy`B#!tj49`X*!zliHHL3>Q(-Zf>H_tK$^5I$f(&w6Rb`kK+CoQ#;_4KJ5Bny4Wekg*4DIV9i# zl6rgA+;G}i{g&NQ+D|a%37TUgj=2Qn?RyZVQA8;7A(=7vPg4=BoJ~q{Do@jMJHmaMlG{KSV)HDh-mGhK+<0nR#PDD^%&&) zjCZX0=hW8WuG8%AZF30o3ql@A7b78D{llCdduP_Aw3W-dpeXj&DIBm(0cb>oZUuLL ztW0go4l|H>2CdG@46nLBva7I>qHtA6I6V6vKMKvt=;un(*sQXXHMG4plK%iG-MP6O zj)Z-Fw6@!Jv<(?6E>~ibzziM-Oj4q})1;dWaG}{76bczY{{ZU_XaF)u(XmOSciPOS z5s}mRjw%zgDqjfOcx_RZG>yWcETUCrJG%f|zG@lmlJ%|Uc7?^XgJrRVvxx(42PESl z;}{v^=~f_HyQtkJAX`N`w6MNOk%o4W+k$cl_w}OYKlF{U1(Dpy#hzgiWl&FZ%MshT z;B^(OT8W;w6v=)TQ6}4mn=Dl$CPgQW%y4oJc={amsIB9*iUBMaeq@kH(p=dzT*v$% z?f?uE*z?x{l3kP9?U8Q0xen<>HwHEf+annSbJW#4sjXs++rVyL%3gQEcE}GTlhZ#= zI@a)NXwgBmjUchG26QV8+N-q5BCunOV~mhSInQD$iz0bOHJKxpBHn3rIE_g-;B$Zn zBzw|C-bjn=&K>8AYKUB~lEC*E=Zua!ym1MYdEiJ=i%wSGVN#xY2``a5r zERjvT(ju~NkL;|c0Q{#p1y4|T>M_=d74(2}NsQ&;Xt#g3ho3ypqNLWJ5^0`(qkq4J7F3Qw5`iTZQYu&ur(dHLhkeZ&gM+ zmu3f<89npZ^V+3-j*z&HMBIwF5tb!L_UJR-s$zJArQKFASg8Yc+D@bDiBo8X^&u0@ zBr#iQ@s&~%4a*4bak!Jmy-5|bdCIJJmS5h>B&^N2jlf`%Fmewb)Z!$X3u$H;F~-d@ zJZEzP30@V4jV0nnLGqjRq_0D}jz`y_xN~Kv`=;zqI=WO!+ z(7?3Tjj}W#kU0Y*s626>W6;$(lHwT(DGC}Tbyi+mJooh;p0rB?$8PErF}B<0POPoD zx)2E9`qhhTK{Ra=TQ$tcyRH7z8S^2@TrNQ+P6!8%nCV-_O6F6NwuM=jZL-dvB$z6Z z0molnPXo0!((Fdp4=~=y!av?I$4ul7{d$l7wI$oxS~a#r(oJ)PO}6ao8xQYbVQ_tM z)7p|&pMRBcDo!1T&4c%SYNaH_2{uhV%Ui`{Mbvw)Ev2{!924b(wCB+A(BR{>O$r2> z;PR7AY7ElMHtr+<7@j%l&(fV}V@XzN5TpkS6fAc$C-IPRh552T!QlGS^&4IIa{}RA zeCOvcA8&8R+PLbeIqYndT*nED%2MJ88PYY6_hTw>I4h0`@1EzAnr`VL6HOEqpD|LuL;Xc`0;JyL()r6Q&m%FF2ku%z zHh@P?dV~FHwVOsBNvB5L2`v!_#djXL?cbsPl;bDN9$CKCW4}9LkP<%;f)w)VYTx%s8Slqa=Yjktw+eoj5%1*K_+? zhf9@vryTCvElE0|hG{LVuFNw=&|6$viK8qJ1(5J?dBNk3Y6L!eB229o>D_l*Miw%8 zDmIdM=s3?_DZs(H;a!|gvVQHPATb{Phc!D|q>wC0Jbqd{We)!Un8jO3+hShoPqhDPH&zkWMZA}T8r(BGOUuk z0erW~E3}**eTI0e&K*pvZt3JnBFT0N?jd_)`=>l->O0jPJ=z!YVsgS^CJN^a!>G^s z{V7kL7tWU8M!sWt(ZB-|J@P*f&bi*VGMzqFNFLo*SsGbHkVwH@V&2W3i_~Cbj(Ost z8?E9ur7vzCXTUbDs>*rEB=e5g9P>>w#Mi8`MXUd$N{o=tl8&(w7N!1L?13Y zV>zVLgA}83SOvD()<9l)WDFhPW>sF{TyPIVgZ(NMCfm;QCH>sN6|nhIJx{$}4u%=y zp7slQrIY;@9zc}D0G}4h(?QLL4jht~a z5?D%zOxtsoT>k)coN?P6Vx+jcn7zAwklZA=Si}GTLI1uC6_om8IHy~#NV-|$P(rT` z4(11u`HWO^2bT#XN+D?&vc)FW9CgihN>@Wshdqlqk)JTX?;10(F~X8M{y6Ra6=W%v zHfCiK1slF#dH(?GRS23WmEzqgUo0tC0I?u?@G?)PDmd-pNF5{H9I~gGwpkg8Zp8D* z{{ZWIRw>==Orv5)k-{~*rt}vIzHSCob*-0!BWOnKf*W_4kbj*}mf|Ygi-mBe}P2)2ZzV z#sTCV$BY6x@l^-9sN)ko9i^sP8;GLwv8>`YJ7iTVK;!}l!Ox-Vnxg_Ylwi4(CB_}13QDL4JwWTn zW9?coTtntg7Un4*aZ*M~tNlK`szUcj$6GMk<>WMi}#qTngU03+B`v6DTbnWIT(GHyuO z%BWoPk^v`-;CJ=rsLlF*VnjSdU%t+Z{1ve`w&u{7NO=`~7 zuR+Ut*G^`UVJi}qU9bquU~mT?dm|Yql1)94FC#aiQY4fzNQ(O-5rT2Xah!3Uq}2;~ z1;wOs#{nwJ-fx(PYPNg#9cxT9ND|BJk|c$gwo0DuMF>g2%q$+>&Um#K2sIk1>+6D+L?2XBg)vw|cnB<8PI0Sxbne zv}PxD;zhX>NAjr$Aht&%+y4O7RU)=v6(pT4*hDC(6;b z=JL@Bw?4V`9-j4M$QEoRK@_%@=t+iYn5%wVj8$lIO83x@WGIo$;!>#V3@Vas1m~#( zf-rOK_*3sL8BEZ`BXMOQ$!XPDPp_d;ILPVwR8vn4-Pw^XBegO{e$K!#RR^dCB=rNW zR*4qIQ1Zhp@&`X^^2f};^MFsTM<>#fifq~t&}{bWZmjc`4=(9Ev3}FWt&%`dxTfAfCToJsZ%jMPkgNVyzm5K3tMxF@(?9))`2W=k0I0Ml030E&(fYY z6C95l?})O#2_S-c=8{Onr#@ByJU(*F5A_^ZHAy7SYLT$#xOn`q5M_bfq+wJKexKyk zE4h+M=bLDS6+Ffz2*4Q6U&gG(GT#FPcPNbtG@oaZRaqCDbI3S5P67NX!4kCPl*V0Q zUn~_3j(QQ!f6wD^sTm-qq(>rK&uxz|G?JjeD}bbmirzVG(pSBf*`y#x5x0a!p?L~0 zJL9SDa!*=iv?&~K1c+psJB`z#NJAf?>GU+y8qBi``6RZtGB(eYGd4LG&q5DzTI$Z& z-p@kPy2A0IxLJ1wk~Ncd&`06HsD-5WGnt?wIb?;r(3Yk~Rn9WQBO^E;kG)@o&CK%2 zaesS%bjU&pZPlb_BY~a|C$C<;DxAhUor zT{fbL4g?{U zPqaG?%tr)Zjz)9o$2q~M(p8MvM;oI`@i& zj(8@ix)_L9Ngh-TCnE>1;gR(p)|8}ZqNAyxCCj|6B7moc3&z9P)mycrIBilO(qXOF9qiH0!Y;0Cg zKm!@|{{T6q2HBhCGn7c|%*srWLKXJ0AangQT9Kv9Pv)eN`AuvQV=*1--lXRo`VM$L z)l%8z+Sdr`jPRB7V4L@h&72UuagL;M`PJ)leRlA?R@agUhx$`X8nZA{jpu122e0Gr zS|P>;Nsr7^6q87~Q<*%%SV(&N>nPJdk?#s&_Y6DQ|eu&lGN| zp(A29G>kwTbwB-aP7%l^Ra;k94i%%CaU&KVd9nZjOJ@LQ1046PCgsoMZ_CRBPAy}P z0#t}HL^32KGLDWx#^Ba z>rAw1+Tup?Hbp9(qsuBjUI#rn>r+~VCSW3r4?S1QcMPD6lYn~u1F)yv$#T%aX%*!2 zTSL8Lj^yElWRryh?&Z1T-`2N`c}(NYCt-;_sY1^2rubx8E#qft0S78r72CCmU<#c4 zrz56fH#bYQAhETIJ%H{vgb5?$xngsM01y;)!0u|JhT7g>kGbrdu8_eT3n_22ML1`X90m$M1CPi0)m4p=5@b7~ zQdqV^F#|sR$E9GTs=iUqD&^B8Xs-TZ8yMm{$s1Ux?sz@8z^ie~X?oV8(glv)qGgCI zZ5pcMjDvzP(-lk@EELBru}NK%F~7>m2^mwjx{=&eu+5n+H^%XRnO~b2_WpHBin-4? zyZIKH7~1Y>%=@>%sBOm^Ks+9p8R?PN2R&-sXbehVP|p&UoH!v$`*GVp=QYjUZkc18 zZ-y&;Z3xVx9R_jKbI|emRl@gH%?gtw%P-wI+82zB`se)jrwAw<&Xavj7o16PFj=C! z-UO3Os7VqYNF{(d1dwsYLFDjiJ=bd}M}jE{aLmel#a+LK599tcg=UK50w+l(iP_zW z+s^}vjUMWGZUVHCG)l3!jO|unGn`;#W54TLK{OnQvooSdh`vLUBDAwg%oSIhlZ>2x z8LE?C+v(7x;{{Tvkdvo@yS4VK@$}Tr$R|h9J&&&wpjQ*5Q zHJ!prk;n)Rr4@m}T#V=GRXZ0-F6kSPtcfhbXv4`TDumMS+e$9c6JLkgl0!C0Pn z3BczZkUHZ%YnE`6mC@J94pA*an}k@f643tu65&{5x6`lx0IHd&#<0tG<>Kl#K_%+O zDr8icQvz78LWD`ih4shIOJx8G8ojkW5T)(-v@~&f3 z3or`U&fq}mGCPjl>Wsd7DsrtLAzW?z@I8OedeD*ykt10z(${N7jdI|$YNx9{GT$#8 zC_HBafmeM5=C!i2Bl0}OCDEmqZs(FbvjTbfv(86Km0`A1nH(7vmuMd_^yZlz%GOv^!hOYb=QtVsc;={Dq)wn0FB>>z&`$z zz&wbE+{WTK17&i{f_dlI%qAQ#c-6CMgjjPn8=5S$)65 z-m$dqQnkx)YUys!+(eP>Lan;u-6Z+C06_#YoOC>MRGw*MEJCcJP|U^v7t0)zoZx;R zkfv-@UEr(v(thPx23J2{r9LSNokkXB3L^|T`B?Tn2h0g0@vWf-o~#_1G;l*8j##If zSdfzp^L(t#**`EnIpZA%ZUCskxK$g`fd^`W`-#VXJ%6oFX?5k162k=1vMQ{oF!JPSi>&XR$~gpMIKj?&9-j2&wNepW?+B$__bb zM=HS}mKddFnc`vx9*62booZUe7@9W)Ik)}naxei~ka_Mo%~dfYHS7y;#6rr*Sd1*3 z@x}okUtYXcFmrCm)pGP@RZAN=(8J~jW&Z$3k>m^rBjo{b4+l9Uk&J#O*x_&LPB^PF3yD0N zkXQ*fENIKZudmSc#Wr|~yiF90RS=}RiOFo_XY137u4iGiu1jO)s#~k9Qi)u#GSBlO zXVV1!AJVVhTgcE{OwOVM8wUBpvX4;N;QNkiJIG|p#T&~fmROz4%^MSw*OEI`sHX=` zxVF>)^51JL0f&T@0<>s=IADn!(L z$c{58m7`2zUEAb1^2+0&9YJ4Tr@m|z)GfzFebWGP^M>o`=3c{+{&n3{ppO0<4J`WrTTq zm81iV_Ulqx!tS_{Ko6haV0^4PerJk&R`Rfv+a<-@8C1QsvI0rzpXvD3xkxHaUH2ll zNo~H(b3CjiSWlcF1wbb%Kr32x*k%Mtb)e}%a@AoIti zJ^c8gi|qqQB(>V!umY81u>RD;PsQQD@w zds|@}Tdm97AyIK|(BKT7Hu6gixHs1PZ)1Q>x$|%oRYBZ%YP~&@A6__l?wgPeY;T6mwmgfnk*a$r7ecZ z$__J;$ohj!u!*CUt_ABY%%gK3EQZ>6Ah%9)jw(e$lTRdD#5W1IY|L4ey6zls3H>-d z>iOBtQN`>&IZS0GRc|)kRKgxVkgj>)j338?QhlOHk<6q?d~O@}vBW}K5M00WFM^s2V;!x*0AN<8O{RZ>jhWb_#C&U;k3&g0P% zMQp1Pg+Xa0llM!WcY1I?N_=qyWsonRP0Etc@O1C+}s(0+KPF znLRlAQ~uEYQ=>-DFWL!Ese%-C{Ce|O7bVo^le-zRNViSr=8?in{uWCs{a78I%o0qJ*!d= zvAiQ8tj-STVo|m+&&s(cAPjZ)`qpl3lN+Wn%nCNbs~Z(Nizx+4k~%Q zQr)|8=qV+& zx);$k#kIwxOKiLCCSW92{4xe{k@X#F>|x}I1c(rs4*6ez-1W)tgIiP3n95wu4BV4P zB=<`I=l9VkEWnO{^&F0-qa+oc?Id?C<*wHtg;n(b03Njjl3QEqC`!bZs|14KKF}IA zVbt#Fk?s1_Q`n_(u`z`=P2`PLdyPKwYX>_9%^~4@v}27F~&FpJ^iZ0q^v1!g=2^Y-c+b%{=GeE zX5N!DtnN%K77^5_$smrn89DrY=@K`2XOctaHNy`xC`-vFu6yT!pKp44-5IJWvZQ56 zA{8J;fP_)^eLo7Zv(5hiSlE(DNl9d5fI!O+e_VCxRa1#&bhv~fNFw_p#@=$CyO`r{ z(oO&z{HHxdT#nhi#*stH(J6L~n**<3)~lHlQ8dblv&xxc3=Dt(7b?Vh^aOVl=&m<; z(h$g=SWpUW3UkT)s{2YU=Mzr0=^h#GBSIP#UuHcpae`?OMuJGLV)J4XHdth-{{Rv= zKb0omLo}Ov3|Y{@w0YBkCM4W}cDJbY7(IPYwKX=zV}T=fTn2oS3lCqf=~nhY%EcuS z!}9Dhk|bPng&o1pN$N50P|I$SD3NajlgOq`ha(He1CPg_@T})4Te008kvw-%2wcUr zu9$>80IQA%;yaqD9k^v!i%AvE;AWCWBsXz^^gVt3sq#l3oMTPQ<`UqvVM!kSK**@< zBVg_OvQ5BmEgC@EPI`Yl52bAh-CWVqyCs#C2ie*j{{WA@bIDoUPEjp9aW|6`{#bEtS(r*bR{HcK znoy$Hv_LR<-Bd#&klgej`W%c?ATce~!*BBT%F)N=u>>zGkD(kIsd9vDx0XhI+{S#u z+gCM=TREqGUCTD&YhZST-z@;yaCHK|oE=cxuik~e&^^T@|;dsNJ` z&MaC#v#ilVRQawWU8qky^*HU{1JV*^-C`&ulGPJp?zc@s z=$Ph^{{VMr+@*P751{Q@(5g*tP0Z+4WV^JP6oDTRW>&HDSMNyl+PDDp+>k`L2NW?S%%F`wQ2P7PJU_DAYV0MyczQAKPKwyeXptfE?bVf~5UIp*gV3IM=CI zM-;BuVh%6}1Y`nFJaN}OTq0nJ=FX@|D(<5@eR&zk!T$g`trBeBr8qQJR=Bl=?(Hsq z!z)J1wh~rJl<>+p!OG+iNaH-#x;z3fj}srYqOxxVfMLkTzX1%)Y;mU&K@iJ-l)v+*_GuNtvcIIX-57nCtCMm&=gJJaETt50<`U zX_g>oIpmVOj@aP(R%$VW+~}uLF+@)cu@Jf0y%zwCfPbeoIkS-?y13gU4>Z19SS40L zgSZYyVmf-%<&*6GRH5dXqb(EeIbQibze=q?pLYppyvW^$?%9E5+tZPr4svn+6{Xe9 z;@pxF(o1;KQ|1`dhF6UVQp4Ew2i~N$ar?>Sc=kL^<_Gzh$(-PQK%{wQtoTQq1mtnU> zHwwjJSe0-b1_};vewuBAUKmV; zn3ILTkG#O>awdzZW|s` z?q6?Qj@5GB;y|fv&m1iau1qQwn6Tt$86zK-ed?sP>m9m0F{31>cbu{VBC5Fr5Dx(3 zJoA7E;N-_JlK9PVs_OC#zq`tt`2?p zthr~D-a{*@MrVymq#;1uK3p(d0C?}ue|nvxXsx`)A8MHt?80Ml9XQWX$3CK?Xgu_Z zyw`=+Re4$>F)IPaMmQtp1dhjwh|VqCx;DEmNa(I&LGrxHW>CB{HCs(*tAk@P+4jbM%~%8@#jo@rG1o3oq@?)sc#(wL;q zp=Ago49cpR!!~;N{VI5_&B8pE(8eTC%JI16K^$W|k`GVPuh6Oh~V_RQuzM za(JjQR!ElGH93>a-5b8#7dvCdc|VUFepQ@>;*p?=R5OPxdNV5I<37jyeJU%zwQNgx zOEicHy0?MU<+}B3bUns8)vK8 z_D+IkWoZzqFd=ap4u1kapS^3bwJAl~jqfp$cj&ta8F`kv|aILye_Glb9 z6O7LgJqhFjKt7|IQBFnHlohOM+eaZG)GEANM2;}KmymD($0M#iYEmtp?i-b}xBEh| z2{DXs3VMKjI3Jg_Y6y@jY>pIW-Q^hxZ!C8w+uPVyOv^IN%^PMsw@+Vh!j!4m9&DUZ zWv4>SBq}Ebvw^?|x8qq_oE}7S%^ajWQMSPpp@x6YrB*IOO6Mbp!B*two`27!X6o1G z)d+>jmQ?u|U=?4dy>UCIsm|rh&OcYYo61+3SC(saEw+D{sy9!dJ$bDiF7L}n-EK;6 zRf^)^?qay>@|<#c#bz&?awM8aq;1$&cEJIU^Zx+r(n~DXu%v6}-71i%xCTPsL4nUF zik@G1>Qa;vI|*lv)d|><5>N(E%zgg={a&?R_I8nHP*OnikKZWT*vCKz=1UpYiIi+%?=B08a ziHd-S<=#^Pi2k^%iFjE9NKA5qp-=&g4u8U|&kQ#XkVy}daQj{u*$)MPBd<6kk?d*{ z028p3kfF~w$v=WQwn=a{w2C@${4L+F zZnY%Au2L~9Vo1UUhCw0oGC2qrju@Zi>S^>glwksjLT=)gVQ}Ct&l_B!4B0(MILFem z?(Hs1$_3rk%(G0QIdB<@=eQj?>-FnX%XK7wX^@bx<0VdU8lFEx>s<8OrReHRQ{{T9Vbmw+1G%D71Pz$wX7>JLiju5~zXt_8ii0T;`(s(?uBdiSa3W)3oM zW0SYIyEhONU>YX}65*pQ>OtU-W15!L(Jtp}hgX}=#APr6Zb9kCKb3Y+Y1Z=j*3v|? z0}0V(Z3c`0ikXw^r{yKoBG^%?zZS5ot$nmA;N2_sF*Jdw;K zjb!P=gM)*fMRPX@RLEXcSd{Gta4cJrIO~o&iaG3S2HDeCYSyV7kjSDi%)UYtB~Exa z#(5owy>y9is)iPHSODb+86)yPTJl3Ew~{Q7%v3UvcLf0R{!MBoqvb&xJf=|h18Xix zRXx8^O+8H^PgAawSf0;oM;ONJDB*(uYg7AXXktTgDwdAq;p1??gWDsh{{Z#ZJ8NzB zt)=5KMItwlK-@QX&#h@Dh|oQ)vY~Nk%OXb_<}?6sn8q>ef2A$i=t7M-t!#Dn`qWdS zHM>PCd1RPmkyH>4Pba@z4(7U>4OL?RyM&FS-bi7b5zuzdanC(#!*yFtTHU0+kz@vJ zc~N;`RZw&rKp5^$dFHfi?`~uA8v0pdV zGP^@@3YfF*EMq6~K667*wX{VtZpFgM^2Zgn<=fD5Jvrx`^H}mjExS9$2bLH#4Ij!*IT;^b zJJsWR<^80AAC$1S%y6UVKMej=nde;N4<1wR7Rku2XXs@rZH^k^Tog%;)-n&YWC68@ z^R3vfW4y`|e90vJ;2>aQC%$`k{{RZ-f3ft^-g87jEEufrTj%eO?&R_XYYSN3;TqcH z6C7&JvHt)I9+@3`Vv=o{-;|o>#fv+s2Nh1uML6C3)(9l}m4ZaLUoTA{fXXWNGr19C7_mb6q9Yhawa)h9!X;clB?l z^sJXjPGeKCm#@o_{{Yvb?JZFbE@feT=EW(5D4IxF7tB-TtcRlzFitw)5lx<8S{U-C zND3-^q%T~bUO)QvPT>qYqf_#-5&#+CQ+GKw)5CdnVRa*}*zLIA8R{GnmF_Xu9+fw< zHTH5cuFG0n`LIBiO(c)DC^r?_P8*z)$UP5Vr4bk*S0XtXnqQHm8%qwy133L^-lZMd z$2%l9uz8J;;Xl?9@6hr5>mC%5HnfWPV7^(Gk{EUA$69fElH$?STa3jekz*aiYr5op zphyPeo;U{?$o^d`O3cR{$dQ69d0?-wFf6$FanR>H{v1^+M`H}P6OF*_%#JwheL4=c zIkSzzTzN8^$zT3Gt>i4biQzyepQ-1iE0qM>G$EJg3@w70XW^9yP^;;T0CH+s#PV+$ z-XT1cKhmptq_i>lb1CzRyhMzrJ^J;lm$8Uch}D=3Z)IbWY9-Fjn8!km)zpJ9JK)?i zFPV-M^~-nT9jYOImiy$8q)`O{M2(%m_r+Ga3e$;vvaBLyBPCAL@9S7B@`qTZK5W4m zOaTKomyeg|3GeAscVW1uwl>!MI{C1x$k8iCa-m6M*dBxtk5AIG(i^X|O*};*hC8JT z43dR1WOdt|`i?RxC@3Vv#nh$WRU2e6g)=ifC-Uz!4C!bv9MY;qW2o|x;$zqLg1thbRY6TG4!i2TfL z$GGX&JbyZ-?sG}25{P2Bx1Df>pK^wj?N%)p3S833O2l1EO78Ty6PQd=1q#S6h6B9P%o z8Oc%n`Sh$?iz{_mBxWG5D06}aGI3o3MRKM{L5O*fs=RM%tjvGeBoYbr6`DNBA(Tn9 z$r$-d05Eyu{QA_i(3GzuhH%%bAc@v!$t@$anO(r+J^C8w=ki4Rrd-M7vXi*yImkcC zy6f3eSC&VDSZ(BulJO##Wt3+nO8WK4=LWbS&EVf;E-|e*SM_Z zx!VUyM%G9eqF&Jt4Z|s@Ad1}yF{F~ z+SAQ2`Dm`ovuiVUI6k}#{{V$rcSX14c5q**vQk4abRJsn%WeeV`yTxN09q%ry$Xg) zn@MAFBO6#_ad8g==4QZBr*c*p@`c|H&~iD;g~jY{VEJAc-Bp#C z1_6N}f!7}6rbno(&$ScwV3A2~(mQUB;!w@F9lT?pW5@@P2nVHIiCQ^Nn6b@pyOrfe z8;I-A_zys7#zo&!)K`*Q?SQA7y^BZ=2m`V0+sZnj zx!ajiH4J~%u-w?-jQwcyt>U&jR#r$PU$nq7xM9!A#1KZ(Ir@&&IcgiS#ntOu7egs% z%#rXHD)?Uh}55-;5;?0&tfDI3jSw4juXaI&!=4`Ere z%ErxN`A9ssl);Z&b4Np}n~GkAtGoMlhFKaZS~69VD|rf-+dTmwlDOmX>s(H;s91>> z;h-it3i(##kU_^@+=GMs>wPZaHxgN|ofNj`a!RUMc9B9p2h|I&o`8o-@Mc&of6tFEm>ISr$2b-wmGgZQ9>+HT$hsF*>~*S z<~A}|k%63?U<`56x-CFSAren9M#**<8;bpN#!YiOU@(!VN#-)h1ZYsU8zi1PjAxH( zpDi&PEL&(dua4>KymDMd8Y3^aW-EVI+O4F1DWMRR{KkW<(Z9m9w(|TyIWnzT4-9_M>X8j#AA*H&I_^RlmPYhKGn$Ta_X0sw)RnK(`oAS zNUpaC(pw_+jrMgo1oEdpF|SR#vUR#KnM1_rLQW&xrySttgN`#^b*VxH_t`J!wS|{* z&v8ClILeX+(-}D&gPwn_dGU*jJ0%4(g4Ci`OH!9}xq;+qC58bY5sy;X3JJ$N~)J7tuJq7Yh6(oT&9_Q zEv(UxX%`Nsw&XszHB?wa#%MJANw(P!l3mRqiZSy1&6Avx22VL6n{N!!#U`qkT6L?N zY(Zypak*W0e9Dis1Y$vKHZleWCbc~CaDlAiw9??7;K_F!aT&=Xz*>pI zQs{RojUw)qWHj5C)TWZ!4K*T-Ze^N9-5i~BgMwEhk_R30n)G4f`$W;_x(E=in*ZIS74ceRgiFd z0fO9t@9mnE9z&uuGCJoq*XTYi zhfiyZTX4eh7c)n2hC6VL$txy)W>vuh9G(g5T@k9Usmq$>amCVHt5kj4Wvivzut@}L zN{}{%z*CF>GC9V7F7~ecE&%v-Eoi3zFqJ?jIOoaTH4YxJds=O z%fN)JtPTL_*V?|4iuUI6(pHcNB!?eoiBuI4j^8$TAY<{ZKCz+l^)kufq`8HL?l|o2 z?Bo!`rfIedheg^WRphgbIx(=_|i(C+QlTRZ4!vv4v`$l{krGo>`2E>I+~eNUCXC9E9!E( zRh*DrnH~1*jf86<+vi9|2?TW@b5`th=3hDsi%B7n$@0X^F^qh>M{YUJdVLLQNd!`) zLrjY9ISsH7+G;mO;!iN0&*dBqs?CzBKIl7gdCjW{t}bUtCQ}>C>cZ+TnR2HFJfE%) z=~+tGTAY<6n`HLTjXDHjDjB1Vl_i=pBJb>206lPj9@S#gR2MGxv2k_gF5IqJh|WOz z)HB27nc|W;B_4iaXc#hr2PM6^#s|0ILO6rFNoy;|asX4YaD21Zpgp+!YNa{F=y1vj zO693BgnE_%-&c)WM&-k*MLtS=Zlt_n%_vNZ#)Yc4Y*tr<}U;ccjNq;q%@0r zf3>@rVvVacy@R#~ZO(K5`@nAKn~{dlBhgXt!F8#4<|uhT;X9 zZ?VpZh_YNAyZ5;neV_~`crB6Fon1KH>JYrsk0D@)Zvk>lgy0RhJPxFs04uVT+$3?- zjn8e+^#;DSnpTE(SmtJVVLenImmR+oUWIInEE~fy7cv93Vhb@n&%JoBhEnR)t!?C! zdbx@g-wn4F9$A5e0A>%X4+GbKeSGN!7HU}U<9 z?qQZq(4sVq%OC{wT;OCLy~Z=sf-AMO4RIFfZ&<>T#|}ng0Ea!sMtwQ;tvxzRd#PFr ztVt{V!oa8)Jxyp{XwL)7DugW#>^O1EXYX_VdsW(8yw^J^s99((odJ#=l3tNJyM3NB zoy!>+Rx8t=WAEOzH2qpAWVm({LpJ{aECC6T{IQV7<;mwA2d_2Gz_yazTFVODBbOVC zOiX2mLAUGvc&+z{hKHp#0`$m?viCu?RV2=5Y2#f8

;*~yPb8Eu*k9fo=9US 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�8RR$}N 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

l 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

(zWCJkc}ZjMn12{2v*l=0lU?RBr+QMs@PU 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
    N0~rGwhI^kuP(~$bCr}ktg6vRB7XJVP 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τ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≠D=p4z#9leP)*k9>nGDF~ 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

    H@c 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%0D>?^MthEitxat*2xGesYTaTt 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�aByu?OzR5e=$f|uENFzR? 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ʫQM<^sJgp!P9Mx8!l~p$h^3iF${nb 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∨0v@uOJsfvGj_NfRlJaPnpJS`%IJOV=Vj&q+( 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 z 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
    lHOKTmOwxNcgJu=D}fT{GRY403le?er1OGv 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%0DfqG}8{*gcD70hElGt4jFvR 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%0A-N3VMpodA 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ÐBR|9kLTeuS^4C&= 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ɥ>co^_9G)4cC1+=nMvU@Hr>Z@3_XYW z{{ZWwA9)p9P7+?3cFf4I&deP*;g4U)V z6cB`r84QAG!EMC#&!u5RUU_`EB!J5_o@8of8BdE$j)Wp*R8i>RTJ;xu^F z2xWpH8s{G>;B{cVPjU(GT9!A{2MFjTlom2b@?bFoCzId$)--XVv&VLA(@<95Xeo)4j`_ij>X)JH~W#J1DPJI2jxaEt=R zr>gY?^UtMSYgv>?1fRQjwya`3s-v|s+WsMK232Q+ZtnsSN9vT-zxrRE9fKzHljoB3AvAB#Fo?{FXITok!kST^a zB9%8eWdV$b{aN=ayPPNTV+reQRZM=JzbM#o+cmO6vif;c}@SJG9Prx2)7aQN+TC*?F=5$bZMarqdmn6yIZ!FKUA-3! zvBeySl1C}su{tkMG5GrW`%*EOrY4uqE0SI)iNb@x1Cz&EpyN>Uu4F*1G}6Y(^GZUI zoH5`Wow?(Tp8e|V9%4MPC_;-b6P>}BoOK?+;QcC=gi2THU$T-rR7;Coynu`eS8-xb zaC_&ms&i@~=Z6_dq}`K(8zlGt06jk%g5uiq8Ew(6!w|A#3Rl~n+<%@a5$xe?M|TC& zZz^60iz=}Dz_Gyu5sZC#s&3$%f_R6U<=p_1qOFUa~cTHC;$!yJ9YIu z_oaq)e%eNNNre=TmwO4cGKNj zO8)?CatoQQOe}Goxl&2s40G>Yale%vV~B4oiV{NjIq%OM{{WR%z8k!mXJlCtCOaaF zYcn3~KpD+rHFnJ0q?yiI-rRkmnrn1H<%I?(GA@033evolE~1hMp;d+)NP#0BV>cPg zbs*z_dUN%s3so`85M!OAI03O##hWmAmA0ZrR$nm=Sg`qa@;M!I)3rF$Xx^OKWlTjp zk*Ay>Xs#O~9$n1)f=>8>C*l_|7sh$j23MF5HGU@=Tq8DnTzI_5<{a;K*ry{aoqXPMEFRppr#O2Rth+NNkh z1V|b)70hKLU`ftS3CCfcy@y(8%&Dm9k)yb`jnpXEvlc4*TRFxL8OC_;QbQZYP)h(< zA&q21Z6TSwp};N=-8;C!?StG_y#9K%wq%FrlQ%2nm-82p6*^$&2PZsacg<%_r@;-= zNM8A-Xv)U3N>D1EjLFj^Xa4}zPBMLpQfQ)YWtK=}l}ZL?U93mVlfnN0KD3ig_A$#e zN<7Fmvox`*N4qD2IuXY?>zb=PamySilH5O(RjuSO7|OPI+@~iPrIls5OQ;0Ww&@gk zp&3Dt;GRzn!N(oVJ6#w#YGhyBeX;H(y2O`+M$pLtDyll4m#4Sk*A&#dxw=>_<0%le zoG^EYERruwXRl$`j=1YumzD^MrU>9!rYbzv8*)GcoN`DX%hIMcOe0n>QYcLLeY za7Gw%J-DiK>9^@^=0c)%Xv=wNDzuE*^zEN|s5H%7pD8?7z!^Vu@0l{J?UR%5inA>C zP+G{MMf*XW6CX24l6K$)$ScSsk%54604B37V|mf$kjHN97tFWiu*0gU!0+7ltvg#w zyU@*U&|6I!7IQty!VF*?+_3{CK>>Q4;B~DpVOdF%Mbm`ShxZByeG6*x|Qu(ctIn*9V~I)})$6mI)Z_iZLJVVfnWhXD(A|bCZ_OU_0~tswupuhHIkpNYYBmOsEWlo*3uU`W)7I zxsD(sF0sg^e6^L2?+NTZz!~STH2Z*#Ci0S2K3slhk_#%RKak{spMRxPci0?~EP*Ao zbKK>E%PvxRS0UTJLE!P&`qogoKWk+kZab3%PS(1f;7rGak-n-eGal3@ut1Qw-HLMG^BOW7=$GvXSXCZL7A1<^QCWH1Ngu>G823JvQJo`?Pl+Q(XyRzCQJkz}hC5dr@J?_)#<6b% zeo7ePxOI8gdL_d*mPg*_j45v4hfLQzX}OG?f;SGMfr0FOO=8CrJ+=}U@dnjtjHh`WxXv(rdhu6G#$hZ9w-Oj3 zEr{bPs~+qVymaMWe@QPRHiR+H-<34n{>$Fv^P}!#i6_mfKQQkO>=hcMN-sgT^p@ z>rG>X{{H}IA!Ak9yLMW#bqOuRkz7o>LPE^5qLyXrfq~Ex26Nk0%sT>R2uWZ8J4gQjUpW5&BD7Z48-ezvjz(z${^mkA z7VE}w!Kg0{wVV>gaHu!3msW7uUr*=$O%&jnil^@tVHW%Cr)X8z%-=cK739xgagctz z4D_nEjEQ$Ko=D0*>_MND9B=^`C%5_Hw8}#o%*9l~(SaHqj5a#wKT72FHi5r&G*Juh zmNaWyg1||il#`4w#zz?S?OhUDY;5Cbn~+?Sh?E6+m3Jonz%cDqqJm#GbsN%0IFc5Z za+L>y266Alwt7<7$0T;=b-(W`X&~{>BLMXt z^zxQlt!^IXHD&V*vAnxkdUA8eJpM=VVp_Ijme_~$1IKU(!hzLx`X6!hu87*kj;iI@ z(6^pD_9jG*E4Z5xNxN`VJxSvr=hLlAs7I(o(Yr|u%uH(wTej>jamWPVj<`JWlh%^Z z%e$h8<3-;fQdLRpbI*K#T5@N6@8<}Ftj2bC0aO5fZ@_*%DrI<_e$rg#m4s~a80KxW zuFpBzJYh-T`qrdVt-QM&BSR`T@0G(0j-wrT`eUE1b5@rZyI{74INIJAhws`~X{2IF z1cE*KgV=Fg-lMNIwc}3|ZE_YTj9stFu=bHzx&ThlN2vCtW6`B2BhXq{+k8tUylBYG zE@UjqtTF)FI)nWMat82ysw-&je93VmZYWV&FgeETV~p|NIPX+`-#S~R!nuhyHt4tT z$F6@**150k6Flv89P!RqddU=Vl`4HnJRJ1n@#$J^VyDb^jdyo4qr{j}&60R;^N!V% zf2m%1f*IpG7ikPQ-I1LBRTZ`RY>YpV3$3cEOKi^ZnF+}(8w8LJ(gp|1#~hsNyO?9T zh_vyTU^`CL+E@(pf=Kij8L4u%!i=pWYFoJgg%wgIodE>!0}Nx1{{Ua{q_~k~^2D2@ zTm}g3yY8Ry9X^$alPt|(s^=07k?of%8#x_+Ee38p-Ych!ThE{BhF~R2^ zfd2rEZ41eoxx!nQwCD`;DcS?OM#va*w>jt2p2oYTc_z0uvP&Zf$pdlR5N9M0Y~=nX zvGki&+KnB%Ah<<7Xi}k@9FBPecO9}TV(^IMopI#|;T!gxVB`EL$!Js*IuD8nqp)kM zsa0ZKz?b#+_N+^*$FN~0H!037t=KGvHsC7fJx3Wet7kOJWiSin>~$=cNE-``f&s`X z!w2%OKJi7g)1x_+$b)N%BXX*_KVHL}A6m^xGMpnQy-W8OhUl2Kwa1lmv6d4l+BrG* z1JrwZ)y+Mpjixzx)tQx~m|<9sp-JI}2;_R=xNSMw-eie4WWq$EU`FEI^Vc}%k6QFa z)0Rs@(<@6Fz^j>DmQ@EoFJ;L&$mX+@qS4JOMp_Yw8tPZ_)#Q-pVA@-A6IC`kTqJip zhBL~panDYDf5x?9yG^i(ty|4kUonxyYvqh%0~y>pli%ytY2kwHug@oLePR3j&9l1@Mv z{PEhaRL#;>E=6e^p{7hd5f0fx@)P?ywe=&+a0z@(TtVJz$1~*98yCN%g6r**y|b8v`>}U37EvZa=cyoi4xDzc zL>4ysovXoai3w&a{h&iMWrtkjJvv~1S*#liNuZJK=86eSiayNH##KWT*A0`Lb~xv) z6H;>*JdvFsm;@269O6$?sh|*{s1GB@@Jv1_0MUD8CRw zHty~L&JN+z^Qm<$GU@J>q`1ACdP(Np-Gy12OyfT<1TZ~#_vW&!#q18Nws2uXxv}!G z&#$i{lTINgeQs0nQbQYBJSe7VBL4tXqi7Oz7y$LgIrXk1PQ0?Yk;HEtu3X0}q=Ce4 zIANUjAdG$$+FaSTr6uIjGs|xjU~q((+aw&Ht_R~@Ypsv5305e~X&Xk@zxH&2)?!%8azgILaD4$IwojnWYtJzqjPlJq zZ7iEvV2n9Xt&@ZG8PD^sir2&wq*6yLX8GAwg{sI45IO;#0ppDORU3^`*5!WDBqTZ` z2aUn`K_qtWKc~HNLR{9l=+jkTnFfuk*+cVP1%m40USnt6$fJ(K1y5gE(AJKbaxHIT z+aN_NaT*bZ^}+0O+}8nprds``8=GsH%tB(e(tr`!GJ3BdA8vmdpX|E5yCiQpn@$YC zd5N{zyK&I)bCLaOr3klsYE!al-&4=^?+ux?d7!s5HKW@$R^1D2xFq0)1eRQ5rZJP$ zRt1)q=e+j!ax9Y~jEPV-K;w^oI-g4S9Y02rR*|n7Kzz`)#UBc%oae4^KRyp?lK%ie zv)eV?7Fk$GjjjTce8bZV+;t@O{A-!tQ?iY9)gC8o@1{ofo>N*hi@2LoLSP=5@4?67 zYtFTZF7D-()W%s^S|FtEk}^MwIKc;uezo;U@U^w#z^c35QKOUX4Y^~C6Z2tnfODQX z=cReRx#7!5<$;g}o;}`NO50Q@C+~V3v&?%+g4BTx1U2{j1Wv9j+#! zrmik*CZA6#pJI+CS<#dDiTk)>1~JZ5*E!;i0VkR@E#})rYRqA5sxv4JoF0q_Bh>MZ z)vMrZZ6Y+faARqVk;!wW+stFSHvKlna6*&G+~DAjoMOIpQgka>Xph&Z;^S8@Pj-6t zq2hUEhA3Y0P_o4*+AV{H2&|<_05C{BdCyZ`0RAbu(r@I`p=)P}?+nWGTKUZ+hvfr~ zz;nsQ0q$!50EytfgHVp*eaUVPP%{SFq#OhOK9xsI(&M6QM%GXymF-$F3D3;?i3NV61B&c)y$=5XOVgu{(@?p%OH$GKvR$<63KC1A zxFl`)n*bbq#~c$?yj5XlnmkD^mn8RQ306zPAz0&uzU~xYgOW~iMmj?B2JQBUba{ z3G0v-Yx`vUr>7Oq3XyI3AF{k!!r&z0(|r$5)HG|G2@*Gk@tx6@NZKYi$8*$k(z$aC znpT=xN1R^VhVt)3gsQ{y4W)Vw#Ngy)!_ zj4bcv)1p_9Krq7HreG8imd7M}@H(EH)5O)M2CdZiye4rxMMoJmzNbs2U*GCF4a&oG zfmduMV~xd^1-4`nkUzt{Hg6K0GRd@KAD+f_`#t**CUK5bj-2-c@Wof~t%}*&-8{@z zH?%^sJAB28o&e8$@_v=)TJ#st_?J$WZ!zp+yjhi29jhA=$t(_7ZR7$voQ|2U7hT3H zQ))1!iN(%0T)Upda|WFywWQjd7U^iM8;>H?w1Q8ja7aFw`qs{~Wn+B|vT34aThoYz z#C}^eD#HwLPR3wI0OzRBdgS%ZUd3%Db8b&zI2?H4*91g?Rn)~}iy|vVIX@_gjeNK90@v(U#wg=~tnX%yLTA&KMrd+h_i`R%VB1bW4z*ZqhZ-jzy7KS2zkzI)T*V?+%!&+9kL4Rn5#gda<>Z znwb<$Gu-G(Yw5oXmBhgrAcO(o0UGKx~E_b$3Zn6Vr z-d)Pe8BvbBWPLdm&FMv-o9tjs=>==Cr%;-KEqlBAQ568%I(aHf_B37(Sp?9d}ThPy1>MX$9P{ z;Ubz)H!t^xvFb5d^U?N6Np62O=e26j7dD?$l)lpL8b~iJnkeohfEPnkIO!8*`i=eZ3C&} z7$o-3PJ36*-w^cZBh`MN<{q%*pjt|TMC#V=6wDA=uOAj7Zq3~FWlT~%t z`U~Oh%rV(m`OO>&cL;fAkYz%WMpz8=$4_s1#_=zPSZXbGYqgqN)$-6;O?Zjj_n*rx@x!wYmMPbExSTH_HjxZmica#7imwK;ZN8+gv0PNjH*UkjT-(365@d0m#a? z894-G@Nv&I_Nnx%+l!wf1)e7uy0}7PWgm4_K?88=OK@wj5!f51zn3#YVo?Q^#&)*k zKfDYGAgd6{Fh>J9931}u6KSxnl$O(KM&^5~K*BiODQP+57#LtOe*^1ZQB8j9-FqH% z+>zYq+PKzqi4|1~$Tv*tLaQF%C>#-!&2CGkY0=r+L?T;@*pK=-jmB3$cn@6qde_f- zcZnNH(~{cU2fq=hOgLe=NAUy0e_kp}%l$=c&z*gFETc|skLR#u>ckI2l6fDUczE1Q zs`R@=P^lEv+4R>Kd-7@j+{MJ0!9*7?isz z7V1a@g&nKKejIrI=JNXEP1G9WP`Hqnmg;l4x$bgF&%f5aUq+d=-F8T4nol;}_U?x1 zp;*()3JbdRHgoT~bLrO>3vls%-7AKhfnwhE`&EI5{H& zzHwhkcu)H}KMbTYqzV3wBFQOjtaoIdPESt5)1`dO=}@U&af`G5zpamdE~7@iCu=l# zAA`w@Q@@hpdnn*|*!`GG=ElvqjiVVV>Ukxxz{fT1dL^6}I+diWCc^2pn~jN+_qgQa z*c$V#5`8j%6x`X#3YlPBq4HH@WzNtz;J199Pd$0BT%YXrH#X2&G#k<_%84Lm#&B{5 z0OS*oYWdhwoo3zcqJ32wDwN!=KgPOjZxqlg780Om5#yEsfuF>m%-0*?*ex_YFVBYF zA|?4sls;Op=y~8UKAxWS=(>iTsb5*zOXY~Ac$u1JbGk)6GBNM#+PFU!%-RNsi8Z_u zFom7$URKz$5%Xc!1b|LgIOsj=lNCxH(Yt%6u|>wEqM5+k_}9f3`sDTo{s}B?uL8Tr z5mr^*#^M-`1~Y+*_sve-rqL0Kvs|p8#Ry{Ch~OW@ob&CP`3u39+qLOteYUnbg!``H zdA!KhOntF2hBOtB+1yQcEUeNPB^#fNd1@Pt+1<%K$Dz%C1Ng~&MDwb=f4qzL z*0(`fgJgl~GuNeF_{t!$(8ZHTk}NjgJH@nZn|3lJQbR7>9P!lSgPP$!4#e!+WR4Le zF`b2@3P@})=c|0Yf`1C|=a*tASLIIXC(*`*FQ~b-?;C#=wC8y3aSTfY7U}{Ms~#GP>;4g<5RW$6+7+|7)N^pLuG9lnazhW=0)69gayGGm;Hzu|g~=eEypSue1%ia}E~1XD9T0JJB6(h)9mIYj zis`<}%JHhlacO1te=M_M$r$KI7$9?A>8k1=*w1Y#{npi3ZYG3BBd8xMU=jx5gU7Xb zN~%wL1e+dNl16z_QMO4Glk4m6_}8S~X%k)P63!ERaHv?MiAtza1_!R?;1kllT)r}g zJYs{IDx%c+qsBJU+QKILG&0IT)qKq73!l6;{{R*-oQ~D!KN0O7!%NYknm@E5)K)o8@EN1QBa%2IjD8i$d@#GY zk6CnimfL%fzcVWwl6`ZWcL%VgLOl4bkD#ulJPG#X*0J0y&;@sBqb&0AwUmy4bp#%# zry{<2*EFkmHR+akC6?ad3o69HBn_VD2aFEY?NRHnz*^>60+fsgl2QOn{p_CO7&XNB ziuMUEZzM#wyTY=?cM<`%Fgl)i&m50h`Wa+&t3_$4rcYL-H)MHz&Z8HH-uX?W@!3fT zTWhl?-I$P0c=^6u^u`Gs@q@wY7w|jaI>>G*Xfj%`-D2x9?*OWW#sOS`mmL8o2N4DlrdD6yr-gC z_=f9N)b8TCp1^rRGX!>#I;uun?kQqUM@*i$>t2g}rP^OxLdMx7cEhx?6)MS&20Iah z$@Z_CV7k15{@UtQRC6qCwOen?>w(k|YuH!E)<4vrsknO;_a0&KGSNCzAk?cMr~3< zC9Jt=M9sU)lP96c80SByZg~Fy8+fx+)Gy(<8o>^ zRHGMTrFf%%w8FO@bmn;@3cqqOjtD&&PI`>8UyU`aq!vdHbh$Q{RC zc<1R|d{@F3j`lR!vk|;VNyZK{>B#>8>(^FnwC!Bmx`8AU#J_0X3v7_F{4vNJS9Lr( zt!)l?Q=S4!OH|Hh!uqT+!7tjS4-93bMB{RjPt0@M`C$6jpkJlLHb!_^C4mx23??GX zWFX)kaz=lhdF9QC@TK%J#}dk|Jc|Rd45Z{_cMJgM2E8{!xsLwQMT#|+FD5@Vx+!k| z0F`&)@KdK9j|Vis$J;9O){K)xmRT*W7UuTeIj*hMe3Xtx3J?6VK;L%+;GeG~8tLZI z=7BA)EUsHEYRZyH&WJY2#icxoj+8_;B97-nDS1k>}3`QZlTG+bz1! zEb^pNGkxG&Et7&t&H)1hw_#h;UQBHzS(es!igu7(!D<#}1b-89TNoX9^siEtC`Ksx zEblIi>NgXylE-v*fyVOWeVHSaGct^g&FFL3{c9^&Ye6I;8%_TJVYV^MKrGCE`q{@A z9DQrSykqfN&%*6)`i`?{X>PWx(%egQ6=6}InX$;})AZ)K8xPuF!*ey1X{lS@8_nOp zg~?MH$j?!O_58W1sb39EpPA-4Z0OZ*sq|rzYdQSazG$s;feK>*w*LSYanZP<9c=;) zI&14yZLK^P5?%R>RG`?6Dz3k;vVkbb$X zf#Sf>Tm;k}VLB|6K@_D_x2YbW5;N|7YxD2^7tWO#o-2ut%Q;!Cr-%n!=Z0W&mBu*c ztLY!K9+7Vx#xX6@rL?TlTqnw>2MpNgM+5`k+NsoXMi`7H9!|@1^eWq4xSXi7M7Tzf zD?=5Tl4TyMaDVaNr7h2hQ5xbqTU44hwP_-`j#e|f0(OQ>?NUz}&tYExX+IvWq>ei~ zfqx>LM{Oi~m19;pAaF@su_Uh?oSwC!zY?`8?Ltr7>OW_KK_f+FbLEyEnaKowL8wrx zGoKcDtf18CySl=Ldthi~tW_ymL}t9mLk5?&pBQCVwFV zsFd@yvcsO)0QBqLzEZLArTy)jnf%Lb^Btl{itZyl`;qPIT8n&c*3wC=jMCl9<;Qp# zQ_Ea}a(K>gI2k#`c2lJ&>SpU_MBCC`d)E@Zh7zS%AsJhn#w{SO@w)p zhBLNEU;yYxQ=Tv?l~%eQB=FXb=d9RjS1B}!9q@)bsZPsR+~HfXIqEsU=R6-;^eCNX zX=M9UKnVuH{8Dy5LOJWlABA{mxw%_}^W#;FUc7L~vM5$%86XgF+;hf%m3LZY>x7Iz z?j=ydW_KG(k&p4u*V?tF?s)i$Nc4+e-w?*(l`Uj%H5Egdv)^$!7|$5v`P91TZ zZG8_h;pfafBa%b9GF-%)j4`3lrceI>U)HarIkZ4C~hW( zRF#_JYph`yt1&05`h&>Fx6>ju(%QUI;xHMO*^qE?*F8Ds^{TRDsuD=B_jeZT%^a@| zNd=;82JA;2MmVbTJa;!lOD~%f%mM&*vo15VWOc{ap{V6K!%GI}%m7<2Wsr9~ay_{E z(lcPjTbj4^1qu3Y_~-py^rO{ ztC7WX3@jc?aT}HS_ibg*};+T`Q6M%#>c!K<>|CB?iExOFKQ*yjaQ_ovMeQEa;L+KBINB%HDs7syw9 zM;j|=B~J$Mm~>Hb}KmMwgP0Jd9h`Zc3?+~_l>74QFS$c2U6E@;0QTNHP%r+JzbMtj7Mlc7d z9@V54QjqzN8G;$VeG1LDfEZwO&OaL3=;TY4?ozr|4d$_EQAf_~*i~NSp4j!RSD7M> zyv0NNkXe-Ssy|MDrDx9t!$syi#iCet`DE@4py$&a^Tj_;Xr)msk&;^qu8Ig@k`C^2 z2fexJ^!w=uj)3@2<@V&yWwLG&Q?sOE`f4yezy z2vHk=L}QS4{{XUiZhyRML8Fc&w2s&UL>O`9{H&m#n4ZLR0Cn`Fs$9-8V4zzh45d|= zNTL=ea<67RuzHWw4)&PHRNB5)7L;Yt$}=e*qmfjtnm11}RFEBww}7Q&_wGelibrB3 zxL5Ln?cRxy0O&aH{xzUB?p-$Nb8juEZOaR&0x21AzlZtjO^Ljfkzu@z!UMNz7Rz@8 zo^lAs*EHdB&o=m{mK%8h^VU0XttW6kVU<4hRzu{#&gh0gDgFL%LFXKQGyXNAfc0g& zsNGB=GKkN$q?>*jw(@xC`BZX89M>S2l2w_RpLSJUvG=ktaya~jN#~i9PZC1TVo~;q z*q2o#^Vhc`uUf<*n&%`TwwW1gd-b(e-jay6U;s&M zoB>tgw|HP_)JWvxe2OxvzWv2ENFq`8c1X-{NztSEQHbLh!Qg;Lr>9)3EaErZ&g_#c z5kT3&M#*EIpbj|qK9sf+a%PM%w$0Es_~iMTR{4l;PAbFPAY~vu0ce#?@WSJCF1H>Mu6u%vlUg0!XT=vfPH< z&s6~Yx$A>g$c!wK{hR{%S$Bq0w;hU+_0RZFUE|n<+(;c$?C&DT%e!Vat_R9WoMe47 z*WA=%-}hc*^1P_BA1?&$3=VLA6Vu+TM#g50#-ajZCS9_f!Eu5*kERc=y-L=rH zmPFiQDnguK1KXaTl?HR=zQj`qg6|oPpOD$(c5&;$rq3yri~>f5p_k<+0e9oq_=Z1P zl7A&!#dzBuNn=p1n^a@I2Y!bj9P?34H=J5R8a0k)#BRJX9T@iLc%{m@ib)k_Srod; zQQg<%k`c~+lp9+%9!Apba0^{WEX2d|a=$6yFgeCKIrgYLz_Gm9S%Ux&NgXx@~ z{=GUF&zg%Rq6r!%YndA=ByfI4Bc|ZIWMiP>x^zg_v7s7B_VYQ)y}KRi(jBb4V*}fs zf5Vv;R<)WK-WM+Np)u_QEM#O75AdFxXQ--i$ucXT2=5o)nTRaJX9EL*4^#9WwPrO2 zL{;237H2X!W0RBh$Dr-nvYnKSn@yGyI0UmbtYEhDxmCj~Ym#{fpwAfh6v>#o1xE@4 z@~F5{4^mHJ2;hBbu*)MuGRfuTW@3^e1^G$nPbYznz4L%71-*sm#`782Rb<*2WNQ|8>4>hp2n?G#|_r7~9dvU?qyyRq@^ZHcnG-)@PFmo$H6m9?m>G_WR zO-62`EpW<*`<5a7F>o9sa(Cs~_J$KXzhgWmYYaNNxjhla4z23KLAm?2;*7 zM|jcL&2U*ls^BQ~`sQn53Pbjo-(!+dzU-JM zk0M@7?o-MACJ-n}NA&df6MGOh!9D~gUw9=8{2_i6_*C4!XtRw>m z2e9c&3X61ZU4t<4k1W9FKIZ`bRa!|V5;IED8PYY~Cf}4sdU5D-PvbQH$%zezeDd)#M8>xQL;KbR{sDt@~p}; zw{a@Oa!AM2eJGWzZB0ccU4X#yA!%9GRSgl6KQT}Y{G?-mTapi{`c+$oj@sT?q8M-% zIUPw0jN_;I_vuvNxS9)uv>`!M3o8Ig!8ix}`_#~^uGiv4&8T<8B#)aJ>5gj~qkdIl zgGX;02W3#Po!)i048(Jcm0?zqonB?#16eLK~d$?7^pD6tbHvr3FNEx8f2ihl6P z2OM$f*XvatMoFJ-s)a{Uu#>lHoR7==D^X-HgB<==%%8InfZM*g=Z@dwNb)!X&WTBA z)G(0*YBR>{j!6s7d!DsCsj_ZV34L@#mbSrdWs7vP$XFQI^!ahmUgUNi_(;mmWQN}x zpnxcM~X>Ap8T4L zq`DI}t*}E1Mw3Y`yTdag<%^7De-<&$M^61cF-$RH&PIv8)})y&uP>l6%_9T%La8bn z=G=48F9Z?+l}k@1)^`GB3;W3f5PeDXC;C$d`ZRK|W_Lg~g&D^@f%UFv%5G*+vSdaM ztm^TQ6qW-F$FJmR>P&(}e=}m?V~DFr6z#%yIp-fzC^k}3VngW06Y%WD>-y&8BmCkSjb&eF>LS$Qdb=Djzvcy zc{8Gu1UNaHH2A}~L{K+A*EAdFzuX=9qoL%M&!wQp1H<5`}M5k<BS*(Xb=}1_>hr z?*Y{F*Or-fyq3Z>QpHrM`HLQyA6~U2M%osICz9cAq*gJ?wocaZ#nHFOKH(dN7X-IB z=|%2=QL{yPqaH~n2D!QNOM?rAW;y$#aR4yrbH;nrMihqFUPms;7bs!I=FeVxfBLFe zN=`#8eoLu1nMT~;_WUYozRetWQTeJD&5dAFxXCjU(Le-ba!EX3b+ti+X^+%8CnINOX2uYN~ET9L}LUQcHK03>kP^-+(Px4%68 zRQYYVs0ae8k=*|Pp5mf&?t({A)02v^3#4~X zuq2XC5s`Q0l~@ds^KtA4e$`aKVnS{&ZtkRLe9MV0imNFkjfzK6j2xVG$7;5go?`i8 zc2OMh$+|fLD=ss%7T{oTPfXTsqiBkfX*NS1b_-Tnr@C1fLy%4~*}&xS^sL*3^W`Gw z$d^#aaH~07k=TH6-!6DHw4x>wq|Em>a=8gS5|&kA&N^hDaC+2Gs@!?^Z6?{Im8A1q zmSO-0B=^r8`cX}{BZ5_@%vFW0*UOx<`P0V2dw0i{pd2Vs&u&RP{#9#YTgW6PDZWqL zWF4w=)crDgRA$%87Se}T-5YM+pYqV>AO5~6+wq&D9%hW~m0Oh{j1C4n^Pm2`Zqq}J zS+VV9B=-cfPqhC4t7zDOB=;T04l(OY-m5x&o@S0X!z6Z>QY%L!hmynP1ReUVU(7mv643=7bUqLjZJfOKhY(C64FQsL6eooJP)N`+9s^i z=tC8y+n6Lsrb}ylw9||jT0+>t$2n2>eBQM*?<~7rT^2bd@|;M3;Dgt>{JEwyqE>Q` zC8#p0!Y0bHoO6Ic1RtmJsGm=k*xXz+zGEckXao>XuNfWtRV&=ZPV9B1q`{{}M7U!g z5<-V+Am@PGfI4QQTT6N2{p6BlNUa)-sp*Vk8SBqI>3+{~at7Iw8CiHLNZ71;u?V6fPo0%td@~7J?FPc&J1zzO+dV18&6|@n} zCAl*~#Hm|}a?Ab0w~zrD=y=CHMI8%LXpt@+QqszV#^F4rw_zSf8R!VCk8pC zjhZ|I^0~%->A}eK99D9SB8Zfv%P_1d<^W{QOG*wlhV&n$PU{=n$&>{O7Ldq3>ehI+ zNt~9Jat`SOM&vHx+dU7i54WW@;y@&V+S2Fk2ZokJX2Ju`*2o8g!N=jAwMnBXb2Li= zh~R9p#`tB9X%#^rl7E#*(KwkykOW~?LK|>m4;aQl9Ood?TwFras4FZs(-uj}pD|>@F@ua}H6uu|+!QWDx(vn$`AtZ>V*S);udJf(F zO=CN`8pWi6qXFA(t|oFCOTbCoz+k93!RwQsL5}sNmmj*%oa)iWM1Y;kyB)ao@9$Mu zVpv-|B7!0S5JqVviH`FaKps-f0)w>_l5jFfz#MZ>letn?Mr)<*+PvjfB3eC)ylqj} zwO=VE%rV-ek}`iDBq3OIJv-E^KI9*`IX^DYz~Fk~n9QP0iTjwNC(Mz-0C)7{W4QOO zdCQh(B;d(Bz3|MD%lpV#RwNPb$mek_o;wUW;jFkdz8K2X7U2d7+MXTM&xm#o}k!tPhMF-IvTFmP12pgzO=^If=mN}>oSZO@MW zBuy*oa>8fw=JQI%Eu{=3ZiHlHGLh-^uLqjqb$FW9a(wwAxI*74`h7Y703y9>#hcSr zmIEAH9p7uHQMuTh0pB2V{{ZVX=C2%)$q(vyPOwuwWVpUsR&O!Ic{)5`LZf9ur$!v`jvj&LVJVj&kI*_Nn0a9`O>chXZ ziuuw>71?9mA-7SSW1}2n7;Z<@Rw`;&#_k)J1a7tYA#=G{ZoxR`4UF+ze23LWN=Y(v zX0hGOu}}W9KFUEoc;}3t&Z)>=*H0?R3&$f!u)@!^;=tjL0ATZg4^hbMWjCoG`$#MxadWn@GnQ4b*)_BxxfnNjTUp7DH-~ zNF4cK;1>SrEDr~q5PQ*Sz8ibpLLid)B?Y{S;gC#8I4D;v7X%P60V5}n4LEY6quX=4 za_n4=>gFqpaAO(ymE$Ca+StMRj-xfV9Cr$?Jo|~2gqVi|f_nqO$JF}PC61vb>X`2y z+If|gy!b85YEFLW9FRx!;<`b1D;9vdG7Os_w(-Ew$i!|kNJ(iFs^BjhN#LBE!$nGy zl$X1yt72{9A#SH6`8yax2_bF>;YM&s2LPVj_3u5ROL68obxU~$M+6?2Kd+@#0#(Dz zk2kwsG;BZ(DUiLP6EB!D7Y)#ip1)JgJWUHsbsP0fRn{hEwZ6H3EXbgNCKb7LCvYc> z<2f8v33XeAw~{MW^Asiy;0VC#0rjlN-XA&cl20|Eh%^T4ELDyRM!v-S#2&uAtD2;_ z+B#zzkh&#(N;|!m2(0Q$D?-s%FfM;bJ2zr44&jHqC9(1JaPKGgfRwzq=X z;7YL1G^ccAoU?V$r$5uRRGR$F72lo)+jeAvZKHEZ!P-4|>T2OBMeJQFkDEkKJ={vb1AtSB`&U)5ut6JQNlkBKk?oT+&GL?})-~c$_$?gl6^ruU~N2{V?0#amE3VkBv{@Ee6_^V$QhZxi<}Ry)AOjEUQ~OyDY&f` zq%s`7Sg5v*c7cq1+4TJ?29M7BN0l)NJ2Hr)at71bcj-=f4d&Ii9&B3#pSw^_(fSOZ z=UMBjY5G)`^GT=O-a&5a&2ai+GD zZ5P??<4b7#qOr&TJ6NtqBZJ4Ld)7tO^!7WVwkr}`ot{jN7^5x@&Vq5su zDD@Q7tZo|a)!B5-E=dK%O2;F6I_+g(NC8RcbBuy`>DF7O9#T0!GZ{7?m>l%$f<0@p znv71o9BH}x$h|P0N!~}6*hg#?gKc7DQ-FBJ6oPx_f%!wIf5g7h;o*<%6TG;U-0+|g zoDq;u`R`P&Bf7A+^JfxABoKMqys~z~oC1B1AEi^gy0U2P1?9@cfX(MwqnRXZmfGRI zUU*Ztw>^2TsLtoLM#&`;lGODn=bH8vh8>S?zHlfRf@FNzBP;W9k@U|s$b=F@B2NT_ znLbU9qiW#%$0TvaFfwvSy>z$MGhbaWXymqqrD5ihTQK@(jB}1X2j!D@Z>K|Z9Da0K zk&Pi?Evzy~W9SOxs37EXk<@TaRJH1T78e&7#@jPF^n}xN)NMXBM!1c<<2&VK132Jv zq;b}vlGa(Q<Briu%EOD(~9?L586stT1ZaJdJNdsa=| z?AJR@n4d0=i>!NCmNg(TyH z`qo5Ncej$>%Mq0!F0Bl6ux-2?g(Coi!LG{R!?!6V_JE z;m;@XuS2)fZB_`?t>cW`0T%mgM+$}DVO4tip8ZW-wvs0=84y{ZAH2I_%m5_y##@hJ zSkvkTYiVJ$xznaw31M5Zw<{TCZU)pib{HI-aB-YuQdIdC$BBx@SH(`(wTrP0KS{NY zd*hosf4g}dvdCIt_j09xVaN z@o`eDETr~Q$vdSQe;aHBeGT(-7`YeHOwoC2e6n-P9#2u}{&}u1R=Alio=MrIhj}nFu3O7JGyZ;+B$u}u zh5R~5+pJyQT$P62+6~gQfbLLwlEi=pIX{g}BRsbXWl%TA9CJYU`BhHss!n$DI)R?u z4RbZhcP?sEPQ}!M7?M`8PNn=pT&2VFo zg3hGwP=7y4?1SxFiKJp)!T}^vwgYYKFnvyIDrtqwN2o?1TWHt`3n*qe2Y^1OlZ<|1 zxt#9xJzN}T39BA`E&1{!xwq5S7P^oKmfqya7Zry%;rynQ*K*8#Mg02-}k@R%wDXwjTD=DLn@vYaI#4l>yyaNIuE5-zPgp&^(P_Og;YBT2$M(q zPhDL$`Rzz;MtjT2Qa!el+}kf9c=@mZQ=D);PC8U~_g8n9B2#MO8M)&dk4_is&1UJf zEl)p|ajkw+ii#U4w#j94G{R&Kp@CIa1C;=PcsU&R&NvjeF+*v&@dTyihG<2^j8}Rc zz_1{WGH|2c)~?*VQ5kI#84=@V@+D}9+@$fGWCrJ^dsYfrYBx4>M|CpG8c*}W0TOMpi)@uI3mS1ogqd zSKKmdgb2T(V3*(e}<2Lj_^;FMM-a#Wre|kk1*jhUNvsT(J4ruH`+?Dl$F4 zI?k?)=yYAQFfOhkSf|v|PbT0;Cdh#&`y=+|6$dovY50WusrU+H5epGmMo| zdFXNpz>u3WLvo-YwL)kg6ltM zfFT}O9SJ=-*#x$igKOxG3JGoZarm7s|)xixKP%m zFvs|T$@xb-<35PVhrCj9hGT3dg$~9)oi8jE`~H)QJhy zeCaMBj>T9HJuMu_A?f!|-UB!p>x!9PAqJdS!{^*Y^4-m+Tt#42ZR~F1Sjo?1bpeYm zH-N-~RF3#MdL5plac?#Kt)``^6L&P1hBw~9TOhodBjwHq;wmd!CAOCKH)~s;KFy_# zC4`vcD#Hbpho{ign+>%7ZMf8L?%=i`X49_I%ds&@ob7dB!Ig+?5rexq;{`O?jcF$n zaV+8TjB&dIw3cneZW#6T>sW_PRkgF0bqN8uWw=|n zl1FakBaYHRGPHzqhf;R|kb0lisM^nQ0=z^=a~jJVOfD_O!l}Uk1?VuxB#?2}wPQFp zC8_7Sl@j)M)xD{gNL$oGU8E*jHB!KDDhVy%En+q;I)WGSI{Jbe(5_$q=^<5c3tki=Rw%9k6QVw%T|0 zQx=8=w+t>dD~t`&NsI?`*DHk{z=7&0Neo}XPo+bSExha zuM+E!O%ko*MgaUk1HY5MnEps<2?OpaI2bM5=M}C001BgAhf8^8((YM&sMgurGD*St zx&Q`SCm-Wi?4>E}cT>)C>RLLQ9xnyB`%9Z~mb!7iRwDvJa5+6O>sPg%J)@Ua)9tPN z`-lr$Uw-*+R7j)}(8!-FsUsoK;En-3Ppm`mtHl!Bd8ww|v{OePl8J7^X~#VWZ1Y=o zzYBa`%^a4RP0aWAk+dcL$Qe>G(XerYk%C7jKIWY0)=m4Ys=Ps!)0+L_vGdlaZ8hY6 zV~xlXKe5_H022j2dvh@y5&#R^oY!BZrM@lTeKI7vw@)wauI=U^>Qr;L2O#w9KOb|p z_$%Ux#EL8mPN973>xhdKAH~4O%1O`QIqO=QPwf8y?36shN|h?jCHja(0yg(rp~NZ@~5S6!%F zEsSI;qf0W|?uKv#jTyMo#c~O_ObiVo;5o;C$#cl zxVA{n1gLGumN#L`7aWzwFujN;y%wh7BO3%bj^aJ6R4Lq}0|UQKPp@82KT{9cuV1&n zXS!>Uw*i&xBmV$by8|7!ZUd)2zSU(vXU#~YyCatAZZ3p2lbe0B20Sq1`g(P(<(6U} zUf%Q?zx!;+l2zEAv*9Ex2#SbHY>9n@EwinEytM$!%e2nWrcdCy#T71&ud!rjF@ z5gU&#;g&e2m@n?ec|4xOJAHW1di3P|nl+%YiFE+*+N%AU)s4mB1qdo^xMHMev$= zyg_ewbb)OZT?{K245^&wJcE(It5-h-C!RHXcX-lLSs+-|V=TNc1Grv!>yw^Mc1I0Y zO%IpEW%$`XUPr0(6n6HrUp!3!`!3w9P()Q#xjc2q>H71N@dBx553p%wMp{1&;jwQsWj0Hw3TCdnK3Zmcu39!MF_bAkHTCui^%T8=A*ySkpv zWVG#pdWQ20a#eq<-$`HKmJRF+YV5MWvc_v{e&C6rJe!*#F1(n*XvMFfp8CV_( z7(5J&VDp~;0F6<()V9f}#TCRb>GwWyxVXJt&SM00e3GreC9}{Go@?q!J_g*&XB7TQ zS*x=)*k)-XjeT%%dhz{gjlb;j(M`c`wm%;)~f z#!|h}^JeF;k}F#)ScSx}Gh0GFRE{t))ZhX$z&&V7k{(+di+zLz+z)9V9%ct7(APOD$aM7QWaG^leDf5IX(LU?_B#> zMQ3w&BcpDA^(aVT8*n(s@RBpnJfC4+?R)TZUbc8b!0VDXH<(E$@aO*k*Id@4;4N|` zd7jqf#cgn=XufO}=bneAPf^BdT|4w5I6Om=_gUq7l-4(TYyG0lUe+S4%Q^)ZIQ1TSfDES}MYtk1PoN2?5idCyD^d9PKE;jXUs_e*gV?CP^CLvXlN zR`UVpAcj()t_Bax4tT0Dcu!etp%vztIffZsVPpRQEYOmBpI*b-xur^I?pPc}HSjYM zEgoxKIhNTLZY2D1+6U!;;+ll7~9V(8mU?+`jjl8IsRzGB7OF2I=XUHl?00DqIS38`e zZA=_0N8&kr+}Uaj*KZ8wNh4cvX%IlW&H|irPhwBkrEE+kwvKDdHMhT2K<^SQ$iW_?uRQ5$x>CrXMyZXcTu6Z9fJZp|Xt}hqx6@$V6}++qIk;sZ<2}GVFx-3b zP^9F{=S@wVG=FNJRW8;SR(4a{5jEM^S9Um3GoH8v`}eEENC|QFc;)kl?^sg7R4BiCQrxZWb}M zMN%WIpP(DydcOC*_)O<a!pLxU37loq_yr1^Z-$I8q*;0$gZ0327PTX=9RvBfk{G;(ZNp4J46 z?d$^Mo;tPvhQMd`KNZ(1D-$wuQ=;pZfVd% zcxQ&;JgB2@m7xVm00YTA`*G@hYqPVng6qrQ8$%VqD+|XEU|D(F&Nw^*dVq7*wOBkN ze+h8Gqw~Cc5b;I5t1NM%&Vb0NItdU*w;++8N1z>Y2YTamKZIT>w6cp>vVu5l!H~q8 zU0OB+e!3D@@R!%@fC+0gq;f^vGd(^4m ztup4^>82>27`DjqZrdN07b?3?ag1}Eka5wYh@k_G52uzGQK_MqW=lq6~j@o(Vk%JmSArJW22m zK%NO3NVjO(Vr02#lrsn9?Mz_p$R7OT>+NC?GnqHQ;!Uyolh_u>0B7{5FRZ`Pp^DnxYq^cN zFj&PA6EV(yQhr~Ua0jS9qP=$S;dh9%>0}dW@~eHBPza9njkBGjfN(iE$Mvpi+rYjm z)UMh)ojY?`NUCD6l$j;K&H*3{pK9Ws0~(X}1yZyixt89ik3wQiP!zXYgXV^pdSoc> zqV<P=GV{{Ybp{hgpq zu$Ct|^4VCNl^M&F#uOwm>pdw;a*l3PrEYh5N}ibi4T%%`^Y8P5`4+QhXS!FRXVS+QjUJ(z`z0Ay~A6Sc58_swBXY`WZX!4r$7x3Rz!H+rlCtwo~ zk`;mA?k1wG7URCBuL$z3&L2v))L@EfW}i=rIpJ@%$#oEu_d!WJ8$T-o2h20vcdWf` zHn|qY&4-e@Y2)){c@NqHWa2bmx>do;6Uf>z)YlxS&JqbLJ65hN{vC18zAm8JtTI_x#PG=-+>$g4Yid^9G5`U_0ON4`+?<^C<*IUWS`|;7G<{Lw zzY;>)L+zdyxcPkRHn`dux);dFYz*TA+m5x_TI#w@)wGvNk$JI1RJR!nrziCl@eEfU zAYEc4Hwg^dNGkV3=Z(EaSC2!-73`WuqpL63=kvbQx7Mfq8p0r~rAgno?#Ik9FmQ37 zT-QWZMIF)V(~Fc-x%7purE2CYd&Y#{O&d*O%nN0))9c@#O6zSeZe?)MBrK_BKGJUP zRy7QunF^kTh~y|4Cj*j2cyEPoZzY`ODdV@6-Ih}{YRXRFKvHs4i~*632^{3ts@W~w z#;$GAAc70aCEh&rVk2CW$01mdM;|fB9Onm`to`+=6{Mif#w$x{Y;A7yF8SC=Z?aBE zMIm8{j3S6`z4ab(!bpUV&@IC0fX2IlHIiCl3(o$xMORnRNCpnITA?jI6SMaPSKIa zOlLS0N*uE`yk53C8%x6&hVBJN{mVyr@`l?c;mG023o|seEbyV_u&!@H5jZ+*dg}SzKy1)7Y)V)`<+u9P{! z9H6pYURsGBSi|FH)jzwFBRrk}KD^%1QhBAGCYD&^xN>8)=kEc9c3ceq01yMOCZd`< z+kg~Z!EF_y#>+pD56nh(k&t=D3HLbWx*N6*uw6yv+TILJ8d@^|IN?TfmFJ^ppgl%L z&M!k&+C~2WEhUITWSa6R;tOSNWDLtDdMNFd$pfxQ^{6f;juhHNaVd$KSvLjfdXv*Q z7z5Y=*10b-HQ9N89qq-7mRX>(nPX*a_G6u-W3CT>!)n_~xS9$4ndG^K;uR<_NRd>g zO13xzgU)-_k&-#N`IuR17Lwo19nSe$79V3`*b3Ypc<1Tsj(D!sbu`rDyM`$m8KFjS z<)cOy zxDuIS13)r5c2h%4QuC@!M)KMpzVYMBV z2m^DD#P#QjzMnz7(Al`L_C$5Hh4 zu60&v?s<3AxY~?MB7K=2;!$kdqS!*al2iq3@L%Yb33R-Zg;ktqk${jp=Sse3i(~CFg?2e0G_6;yq2~T`NiF~MIM$D2kcgApe_8fYeW}vdfvE13qG&7tGumwoL z>JJ?BKE&4E)gxI&os>?qrNXU>b0|FNEtF?^BWvsXezazSJ-7Z3*?zEVk`cSg(fl& zH~@fq^Zpe3{W{EfvCD58M#ZF#DDct8CUU<_HV^AVqWKxTs5KL%w3aK8Ig;Vc{j_E_ zdxi|;oc!EiFg?og!Kb=vwr1XG?I(**zJRWsc{~l|+)6(3qkk6AK|X$`HK?jea_pUim zsLm>raAg?orTbN?n@1Rd)=5l&!m59T2Luqrob)?~q0em{)}uN{1@MSGkrfXGy27g( z;3ot4um)K2$0YSN$4wo|7}3$C`#s1lZyR8?Paqy^dJB7vPDv&6VTEGdlxc#M0CeX7 z=hLa|DxpG2BUtlF$7`qgcJQ^t(%Zc0@|kvq1P`eoBZ3I(ZY5}cfl0hR)C{+wO3I~1MUD3)@bXx6wq+Jok1j9CPhC zWQo8lyJ_9GBY<(uZD{V0-nGIrNfeuRDNU{A^gN!K&w7bVLnTP=4a7Hcs#_^}CIv+M z)JG0;mS8y`9xyq{6-h2Gqgk1k$V8Qu5Fq)#+Q{pkxUQLRQ|!+j+!o7q1YS@2AC{`h zI8&7vV}Z+OB=eJ+r7odtmb1q^VOmTCB|+$UIqY%=`Qo|V?ox}2Fy4E#l5exLfV=@? zVoIy3Wk$uty~K3%AKFG%(Diq*IVG2Oy7s%e`7jj;Aq>d`8g{yO!L> zrF(PSg}~f9=jmEEdSQ+vP|8a%-7)DJk;Z=t(lpyfGONoi4n1`lLQM1dC1+i>$_SC8 zAMGII9FB*QG3#8WqLWP<-Pp?T{HiUC(6-><{o*nXIvj9#>(aXUVu|NjZJ@VXxPDv5 znkLdEN)WXNL`jV{$Q5@mm$9PK_KyvFh^g)y&FcJYsb4wduOAGt@q;h?_X)UFiJ*yaXRSHi#ff+d*agMc#e_?fdarS#bWh8S! zBE@vh%_6=qpeP)Ur1RKgt$GnrD+#{>TW z*IA8e4gTUTT_$8v9kLKx0PuSBC)3ip*yDoYDJ)z@m$BR{Ni2=K%UpEN@eF$YRhZf& z@I?pNzF-lGqsB`{x#5V<13kNBRuhV_PA{0f9*r`XLSDws){566FvH6v@Hrg%XEjGw zj#jyj;jY%li1~s>w=R6xZQsj~{{X;;J-YV%O<^Tqs}$l`u(w;A=D0i2B8d5O zM1#!1>b&-D0jRGn!raIiB}-p2KR!6z$0I2p!bc;nLG6K5%+pz-Y$|e#<|^kHJmWsy zGgrJhY|ZAa{mda#cb?Y{%&i;by)+{!p09Q8djTiRx!A%z}O=e@Hs!ZgK?7uT|e~1ilIqBT<4yoZ8ZWd@QqmdPrNu2@OtLcv4TBe}Z z!j#mNh;8+lHB&f9(rcWN3^3uDo3I>#lhg98jV|^;>tqbiBJL7MBn+UAfOC$#XZ$Og zxA3RfmIaK(9I@Q(xcfV|n7GE$SMKd>o6*5t{C%?v6>{Q^xGPjXvhe*&@0A+IwjCJadJPHg0)R zq_8W%#yKF@u<7?xPibz2S%@rv&k5#nPE$uE@Wrie{HqQA} z7En6igNzf8(yXSn4A-`)EyI{%+Fk(Q7bN{j$OEo1$nRO6A$=z2MwTS7?Yojz0JFB{v*VXE9byH#XX@`MOLP!Chv z2h-TsCuem%t>mTHd6z>mD;@yGbN>M9ucf?U;m9GeeM(rKSQb`T7C<)%8=&9}k6iTT zzH^qx%f3rNu^cS*2twJUQjD)#$p`FKlh&GPTV1Zqs>? z0-=Ha79fC6;Cg|^YumI^s*NaQc_v;IsWje)RY<`lp?6rhj{ROYVlLH+td{SL z$G5gIf-%&8Jke!)45Bc~-dibI!GTn7QGw9l=Kzv<^{fddf=S?(IAphWkx|xJLltg> z8uD@dpsUASdV z-$KCggjiC<8+C>QCzcAVe<&T>jz%~H{W{l~N2lG}Nb)$4%*W@LH}1$&-?o3x zYD8JmM3M(H$2HIH%czle4&)F=Uerd&=u=4g2THz2wkd~7cyKO zvb!vB=NyLi$mjVUY9%$yX6kC}&tbog%2@u;#blaAZ!NcAsr5diw;b0BFK4qi1MM>v zNtJx))D~mG#xa7Va8GV}S1)_wNg=joj!&P4b_4~EJoA!I9-ohD&s}fK)NPqU8)(@5 zq(>oA>PB{uLBZsV^!BVBM;?QX&sSLm!bX!iyr|2!WSNg}1adks$F6%-jYCP%u3>nl zRd}a}Dx`=RRsBXi4i>z``x^ynkc@0u3!qxnoS z35S`JgTcl<{{Z^+v?|=yYaq8%R#UyVL^CtT`?h3qqAZLu9QCK>khpnS+$rDKF8*dUF!B`CE zwnx&hMq^g(voGu|IX`4;SZ@SlY?8{vt8BU=nq`QV0VTmD@L_aYBi#NYcf56qLZAIMkUcnniC2-Q)x|WU}Ps*f{NXPfN z=p1z#^w3A5R+C`jPmRC}lWQyWkq`*8fZCK-6V|M@? zXV*P_soG$@v%L!}P9};*61MeakOD^RsUU(n5!)5srHjNOxK>wv%^{XZ!-hG|7%(A+ zs37Oks|bS!W{x=LShkNMHI6lm50ok>0APA`;+x#gQoAq&Z9Mq17jpvd=G#RIc_^bN zdodv75wrk5ik3)XxRGT-0k)C3S36kap&WE4-}4o17S-m4D>)^-6U!QxNJ=uuP6{Z= z-Gjz)*FK!5kddrP1ixwXW_hk!P1!8O07tHJbDvHsv=c*MouNbn*EcA>Xo5)8A2S6SGt@72AoV`}DF z)FPEcPcHyRF3c*hJx?FYrAupf9HFCSb-9WVuwqTCyFJD^^vBYrhT>cK0x;T&2Je`w zZqHoSQ*x8o>W9K*E&Il+z5ph-b;RrmW(p1g9SG^3J5`Gd*H)G8Za|F8aEf;;XWWc} zJ-FtybsHbFnbrveQM5#5R|Su$@6c9A)9qxIXo$9Dj^IfQ?4`V%_U>>o-=9x;S4LB^ zkp<4NH`?AHzFO?t=AO%%vuAdaZ$TQ!2I3~%ODg((D!f*|XuAgB{Ie?v^B&w0pZ>K# z@CY8`Yfjrp8;okJx1kG;PfX|nwnj~MCZ99itbJTlOcB9W=3ow%7 zZ|{+aWnQ@Fk?BzH3@4SB%vj`&VDmD&Mh*!S`BaFcxwlZk;UaG^lZ+lVj>kFY=}iN> zMy<-n3mF#X-R;{xWJL&?IXW@l#zEr%biwtezFl8pH<`xP1pU+P_?oF{7W-r~1e0^K zI1kPSf30ZSm5xBC=MNh)CqcK|`y5eiON4)vXB~QhjNs=6y$bCj`!IyugEX9?` z))k4sQyDBmu|0U_kLW$>Jhal07*9EofsxQ0FW2y;Rh80T^=%rHmT(SmGsnGCr*5GY z7rQ6B5?!qK3OvY~Puy+D3I~74bgR~{5Bgfcd2#k@l0MM@x@Na#T!Dl=8BX9&eEU^f zc`gN;l0sHmZeOv?(eF05B;Ao+ml_?pd`$t7~hjLaSjAZD19 zSR;)K64~RA;?Jc%KRuY6iTtC2r6IzMjOQbq9^7+TliFQJh%QXlMEui2u@+^>%7xAj z4&Zkl$27?t#T*cp42g2v*k^Vz)RTZg^!7g0E=dt~&W;(Frock0FU($MW+NwP0RDOQ zq*x@nJDbjiIEu8FF`+7qc--IY=L7Mqn|aThD=aGSW~&%7NEGflAb>vb_Z)P|=be~d zSs;5yx6{V^RhBEenO&r50mql+E*A%qcVnQz=7iHVEN|e(gE&V0;}7|1`SL$1v?f_p z$cbrkL`4=0qWBWy?*gQ9r;rbDGm%t0t9Tb|aSJ#mn3aavcBCh-bJMqT%{k$eO3x{F zj!6N6RY0l&fyWs7^Xu%)VY^V7vzhfIWVusNF`lY9xq}_EtML zC&1`O!hW8qN|<@41C$Y<16a2T!2)t;@!eIpz*Yf@uE$<(VgF2Ot1*j(E@i z0IINEmQaF4+R>Ai#yS50^;AY$lF^#8$s<|?Kvg7pEyF+qb_H3FCx9@gp~)RhYe8zR zxhv&JvVGE9bCb}Y&mNo)N~H?N_Gl&ZJj6%#aIGY0cPln?ka3O(t3PX+1w>L3Iqk;e zxQ}d&89RpD{nBu!Bb*#`CbEUa^lH&A_w%G+Npe|odFpy|jD8)dkwYWGR&j|#N#srx zm0{bCynTNvYgTl^3MkwKo(rj9l4(uUF|2XOfn$t}=Nj?u*m1yw0_L@cBIHRNk}QoY zuGtuKfu2bN)2?e%OuRQzOnj1FRQa3@!JD_fcohPW@yxUjNlK~jyl#u#?2=5!z9jpn915(j(8*MQTcPF$CgrY51biy<1EAZ=Cocb zn}`xf99rG77KTTRGOr|j!1K>>!N+l&(^Ax>2&jzH?c^5DjL};NVk_ifgGe)sDFXn3 z&p6mY#?}of;eRzNe8!XNA;}JY=&!TNR?r@l=%_`K3tM0*W5J`0kO>nld$eW}RyD(r5I0_Ckp1=KSw9#wadlY2y+AIja zc-|w;QvTVmM=u!voh8xlzvbky~ zxj-Ba2j~7xNS7^h6TUVSn|;6;V<87UPjTz*RJCjQ?j;kw< zx`1*y6kkK4FlJ65x4A!OnmFZVkVpdsW>f9fx6YcJ541FK`EfSDgUk$ldu=(#P60gE zJ3Yj&01q{>hB<_YklK$ik4$eIk)C%v z)7mw&+ghx%D@m1>=!n4R2--S~ znvz8f@gm16nBi9Pj^d%Q+<udg27^u>lum=4gz z{#0n^c~(2o9MIbY+&f@3Lj^=w;NftO` zwT4MpCA>Kdv7UoDCmo0X0A9ISR#@a8JAIu4XZNSf#&dvABa(iVz2r2vw$fmPx+Lx- zmJRghih@{>$t0VYBFVLg!P;}w`+YrXWgDSI%H=3;E={_LUoi;CF`Nv7fBk=*Nfe?6 z8+?e%zX&E9*?RIif;p+BOJaZks0^`h{S65ji>&QLB z4r;aFNWA$YXx#$>QDzw#@6?Ar3zD6;}bDGsl$Xh+jH*!lY zh>z^@OFM4a<=_ZMUCa+VdvVTK9+eU^#9~?Y%8L@Sob4NX{y6?sR(q>>%r~|vS8h@Re{HFx zi)w_mt>B2l>On4hjPib?j+Lt!($dJtVZJw4DgL@GR5}>ObNjuRM%)hs)Py_z^?-!nQG zyrFE5Zz|nJ^Ea66+k&Xb{K3!T#YSdxEOALA#@HV`pyO%e9DDkYQCO)wt!*)d50W2q zE&x4GZ}ZZs-Rdzy1FAuC&jU1O=sPO6JdLbAU`Qi8anlqjMVA*Nrnz||5X~2oC3}Ta z7*NZ*lhE}Xe=2nHwZYmqEMhaa$-yO*9E0pnA46QVmDHCJ#plS8y2HJYxKg>#IR~$C zTk%ZNVadyjRt)NxJBY{XI{yIm=!{Z+M?@r~$P7@lh=|@|h*y3|;lCc^rBc3Moo2w&(yxBOyuu0B8FLZ0f5cJW5AiokvmAKGiMd?ZlS566KBTv$Hg}3}iA7e{t@4 z&$VLTUc0j;ylR4Ym96AI#gA`J)j?)tHsygTasYP82RI|!obgubK|PFJ0(kWsND)l) z$hT>5zFH-_NT~@pW|fBu3lIS3I6X1VsiuTX(-(&E{L}VlLQGO9>^gEkrDw?&UPh7p zqcHvA>@B!wfCf0{l6?m~DhUXX{hkGBt}VDBPF1}C{{ZV#Qf$s}NZz*9;*?DP0DpQb zBys{77-!`j0S%GYo;@l{%Zp^5J8^9ofumEHkboPw#~mv=Jt)B#Ei%L8ZIV@VJO}kX zMmXT{%{J@Kv>AP@?{vOGMlqE=&UrqZe@f9N&_c$H_iJdN7FGS?tYwH982%B|;CB@T z{mr~q&XQWgCB)9Gw~{j#RRHBjJ8*iOf_NA`YDqrN<(ImNu8a~c9t*`)+QT~)7;fCB zc3Y9i`kcG_gL4y@;@kE;-c!nmEQbuDO!e!?&!t=d&vsP-3vkUIV<$25 z)RF2scd2T|GFD^!iNwX`lgeK^e$=ntb;3+nn`K%d`h4U3u6+nnysFfw@KoCA}BX>J}6t>y(1$qR1W*-;wvlb$hEQaY09B+JQjYSzs)w65{6 z{pvNLhXHaFZOQ06`<^S#wJTiSD_=zzg_21Sx`7xy2OMV{9(&htqBzmyo6LRx0Deux zE=l{i{{T3ye_26wD3aX*v~e=W=6%q)=kpjpg=DOaDNB+@ey1*ywxz8eZ?L>EiQ}5@ z&f6hhoQ!}KOJs%TXgJBnPd9G}vq|2`V2&pOIN^^fs~=DlH)R}pb)}AZ46`c65=(Lf zY5*$49Ax_c0G~?InlP}w%YgSVfPDM|uy+Qx0y*F^o_MHi zn%c?>h^4i&mg@T8EG;8Hn56+EFFOcsyyX16V0GiDr*MRMjXfI1c9IseH(Hcdkq@=H zTLq3D?IKlO=LDFSd9!Hc#*zy80!?5Gut}C$8 zE@RAQdDG7dt0p2=K%H3b>%jwn4tb>-idr1AQ<;emEzP{pm5MlL5URFwxb9L;06YvHMPsVCjczU0 z8-n>sA&`JoSP)3Z`N-#iTU|M5Z%xW5BE6D%rJgBTSsF%brMR~Z<~KMXl5?IpBd&Pw zSh|gy$d;EDQn8hHz5FvSaKzvR!R!ulea1M=Z`t{1i*K^rrc}aYjENRbbNXYB+~TZT ztZ6mOG0NgLmlDQYD3IrZbLo?hOqzE$<~*|RPZ37aM{jWizq`%Ib0W7qVF5TJl1c54 zLrY_rB~di4z{~sDWjkAF>QB?!y&F=3&dPZrVs`PtCBbh&fyXC2@rviA(PX(~mUgs- z?d_!VN=R5S+yDTmAcM|H$4`2w&M6S3sERJ&fy&9}X~N=9B^^TUQ_%2w;~oD1oo}V8 z+(8q%+T7*TVN;`j4;+%q>*_u0ml|E|v{8KJBZ?r)8ZJgV5$#X6y15S}t4_!aYGT-h znnvsgBLw>WYeguT%1-;5;9E$o9nK~F>qg3iZXj@Z#|J*0D>6$+qehH?9j=>e0gSI< z-<*2XH}~kqMv6Htt}U5P$H`)>Ib)1z@ zsEz4PDoF5) z&5wHSwLL5&-T9^|ZKWso(p!SwSm};V*2ozn+;=(2)AXy^GxjHv;C}67igFOCVt(#2 zSYz9-A6|IVlq9r0Xi74H&bFCyCNhX0?5eTs4#As#K4ZWG1o8$r9ZBm?d1n({18s=> zkP>M|;~a#8oxBzubAl_>hMv*b!WuX7402~=e|mKz2s77%?T$Taj;EnTDsRzk3G89G+h=cb zw@hV{;c_J1jyTQ^Mlw&J?O3>IT?s}na}PJ#Y_kY-`I<@X*APU?(yVynCxz!Y$n>sL z#538?ab>pB;sF6!FQT}cFEpIz44?pcJwg0Udq}sqRAF?< z3Xs~l+!;q*t)0W3a!+$uTHc3i7?w!v{G3}ikg^~fhTJAc0}a>wiWzI@I3CRGCF`n5SE5xtG$XjbSo-1DTG#o-p#Sp|`fNp4o3w?m3z7Bl9Ejz~F4gGs*08$EQ4|nWRk| zmzNhGWV5}yV;#Kge8|-G+;;u!bHerPYj<1FZlP-nttouM(JuLBm<8PVJqgabzKkU;K6I(5Mn-D?*n+>J8k+0EtrD;Q;$&yG2i4aa(orC71R>T)?aCb-+r z4__FV%OUe)MOBp(YATQ613BZpd06_=jX!kua@ulpa;WT^JhxZ7)o-;XwuXDVOGZ|P zWP(yzm5wk-T!1mj7#Jtgw5^2a#5!Wf75$n?<;5~w-3d1`o~j2MPD%CYo|S)0({A-Y z5QVoJx0YS$F$}B+VS}8F$C}*KEC!8z1>}!C)4;LEC!e&HT>R{C1_;Mt-n(!St zmX|)C6N{yXwKZ$l>a`cU(PX}xMrbXj)o#{n`DL~YE-n-WStSD-&d>%)=rP*7?_G|6 zvIBE;mv^E@`%je%A_0;>8ZUn&C|eWk=Yt?FIH2A3PuRQ;;HMt z42w~T9{^nanO&lVKvwKH@4)NduX^?|*QrJFpCL;%r-sBYXss*x5quVj*FtM)CMs`c zb(BowWM*8AtAJRj0ObDwwT{)^>0S~s>X#5$$oDqZOCx#koyxKTF^rCfBztjQW8nK+ z%_B{?Q39>7xp5n;g^G-voPBe}c0L@`bqh=D_kvlHDQ$P{$li=Q9AR#jrOFbGMPf@Ay|I*KqQTwY0r-JWNb+HS*a?alDqt z*7|>iY~?0*h(uWmk+ios;~#;m`c9P=kUZByntS<@EU~C*3gG?a$RLtF>F5qeUV5E2 zTP-F++Jvl`B%TwbjB+(vCf4>c&J@8(7D(g^3$(QX($ zy^2cK_P7CBLVjms)G{#O4n1qD)*`dITXTA{dC;y=<3l4z+~GR`lk3wY^IUg?uSJ|I z1c2UGN;t?Szt@4HJ0mvnR;Cge8%U-j&yVG?gw6&g9ZOxbv?TRunzjkr}`9SJ& zMNStNN>sI1X#B%Ft9sIw!suFcmzJ$8fmxZIN;X2aPS8i`&(^$$;(fNs9!YGXl3RVP z=cJ>|Sb_O~##9IE$j<}u+3>EddX^7y8_9nX%KrdtDsr%*Jr7cL@RB{uBJDD(6}`M_Bnoms zAd&c!{cEh!;?s_sHJ!wk_ApBk`#Q|6w4DC{t6T%lGI_^C&3HAP&Y@)-mRfJxZW38b zL}6Xb(`NxxcOt%o@T|7_mYB(?Pjz>xMH=t(VgxgDxtX^D8$Gey^IvPi*Tz*;?Pix= zr^n|MR3RyJFTtkiPoqy4+O1*QpSzF%S#i4nf!o(L;hrUVB)W40g_7MG-r=oo0bX(r zG1L)}k^O4+yDjFEtLj#k!B#t_l4O-745!o*ae^_7dtg@zHBC)5d#NvA4-TN)86#b& ziVjl)p2wEXPkuPBu&GWEw0fVPV=F-=snaAEq76DJuBV3CC6D)nouV<T~MR!*fz`Pjq=TD)U_)Wn-mJB3xWT zk~_wMe8I>PXRo;b06DIgPF9&OV*b{)zMXL!O>rraVI*>_F_X0CAOq8mqPld`qwu^p z4EUA}(s@Zc70AadNZ=8ifu5td;<$|h_6wWqh~^M6nTsrmBIQ(i{#E2x!NU%f-mK1p z_9*52F>^Mbt;l}T_nLrqk5ifrH|+Moe}qHbfB+U^I^=rSuvzO@*0+;d+a$6|&l_4x z1Yj0oM&if60|0j9_pWW9N4J_&WQIv3f=%*U{LP++C)DJOd)KIF%cM;_4wnW$GQt>A zHjB)R;e#Jt{Iz@|=V?10-d{g|l*H5(A6iMSEt*FTtdZ^9T1@lLPs7^1 z%U5}Ad^~OvP@rN-(g{Hdq+^rVgZ_E01H=+ro0}KYE#BpWZAfi~Wb*;ZW-LG z&0EHEm}0ZFwYas8SBzf^)?JSvByci!01tmsE9P;OVTGwvneKhIT_sLOBQCbq_p7MM zc(zRy!SmpfQyG)X}CvqK8`OiG^ryw6;UJ>F) znHAj@H#W|)O(ZblHetsc07pUTRK6ceCDq-^GqhI|T`}77e9|!Kk8rvCg?zm_PYWlb zl0KK(^T8{hY+rb?-6FC}X+-M)9$IjvV+XqSAa+02ywBq9sSLV!mF5NsZP&|Dg^`Io zk~rzd9jk(ZX{|MjIj@b>@LV`jt0CTUNG*|`54bq*RXka%2`>^^1-Xr4ZN73VM#v9V zRv5^}ITbZ?2>Un8wml3zeoD(?$AEOAZxihC#pMV>6?hg_3Qtf-ILQZ*+dlQ~w)(&J zb>yM%B1j@bxo&TQFP6DtA`U<~%W%At>P>K;3zo%n>*F=W)7#uTZ7FIQkdBJGdM|vF z$3B2lyj2Cg_PGp6rrF%RwX{2RD8mMgIm&=Y3VLpBxg-uvZ&oo>m1LFAZwlh-H)6-d zEmG3{&+K+~`#ix5MQ;Q`J+ZbnoxJh2v+viwY2OHRTa`Bf=80|GpDEG95P;!w0VEy| z9e+CW?MU9W_>JUfE~7)TaJc=;E;0CyIqECg{ujk>rdi5wBwJ930v22=XP@a_C0M*x zB2BGNX02P$j88E5jpPpz#<8@wH!^_NA!KGC4tWHeXCwL7qj+0c5a{t+$|Q{LERe*< z0b8bX$j3}qlX#lv&heey;lv0_MGV6LGR>>eJ|SL_XSyUj(9IWx2pM`oEPG4H1ybfhis*7EU;z*xW`$&&_&2l`jakdaWNAW55&mrm6t$QT##M|Y8 z7C$Q}Lo;;72lcM}HWsxCv*w89iBF;B{{R~Cty0L;>F;xc`10Pe9>Ffn@8n2Em?pkPU^#IZnHMhnJQ9Vy-)zF9<2->X;$-H)|M3c|ja1mg$)0IgT` zM7WCaboi1RmbkLY7duxzxyL+nUqk+{Q{-A7(R@3Fg$YK;;$+g+T{_ZnFnO)687&}} zEh0z!C+K?TIqRCc746l8v)S5M!En;S<=mTz-Vm(A8^fkfSE%YT25X|XxU{z>8^IbE zR#;pDNo;-I*yMjY_~}7nk8TnfMjf*2=1g~(!FfIER73WbMX^)aL<+Db0X_$=jjPOpwMy57#XV1SFG)tW>OIxcc=W@GN zH<5g~CJmCUB7%9_#s?ib@N3RIG_h(i#dD~Au1h~ZZm(?{G!rr?+z~!@!p!3JId3KFu47zroEO9N>#D#y-V2~Kuha>@yyr&?X{{W48Ev4zQ z(}kavC=siZwSs}iOyeJiIpY=U;pxgK(yNteN35c0OA~bQ_MRgLqkiH348Oc11 zFwQ_Y{cF%Pk!53bH`(@F+bfoVE|jOrz=b$g>M}UwWMKRFo{@cNJ;QH;_I5(je(j3I z(*-gC^ew(PIC^!kh*qmH%f;Z$Q|zZsXLxn%8g)BHhc z751LH?O0#M7?XLEqnK3+a-7CFyMeNQRij}S!)U+J;1x4IXxtZh1xxGBRT{d<$? z!5s}PE5s~Jc9++T87}bAOxfP7d*_^tk%7i5qSib*%QTv_CNPm&f>ulbGI%S4o}ByF z(qZR8K>6H7Di|tGjeVuF)b-oj+jq5r;8;z>xQ1tF*Qm~RH(cOyMmvh)H7m!_p_Q(D zyEvzHOLdzOuO}xN``l-xO{ZL1t-MMN>ny}7&2GUlkV!kaA%_^iJ#+Pbvp=14^2Kp+ z40fp-OQ^~vl1VX_b0!8@o^l5qj(ghWoR5>jxYNY@J6=f;%@nLI?xymO*+dhF;YdLH&b$TJ2OBjXwwi&;76l}zUpYS*%@U7K2q3hOf!uj}6*tcJW87*iYuHiwrp`(laG;xUIh7ryQk~^4Pn|3IA^!lh<>G2rQnrNYIB40tgBffv9sdA_K7jTo>tCE&oz}l) zd2MYS!mYK!I^07%Zp|dX9uTR(Aal`Djxdh3$qQ6Yd3l0~dng zk!?~-n>ZFWK7Hiy1quP`+d(7%GEP4V>6^lK@y3zEi_x)KV*=zaJYevB`NvwA#m3S| z`Rci>V}4Y8!>D)*T9qtuB(8}&vR0B2B#X2H zrAh7%anG$>s#R#CL%S!@?!wbKL+ zqJU8wVLDX(O&k z?^~KSjckk}mJ)(EWEQsbIb{d1zvV}Lf}8tv#$` z(9(I8TJd_JZ0vs5t4CsB`(oS(x6!WWvEBB2emCZxoFRtbH@Nc~ZSc_*ZugoU%tC zS>jvy6LE@JfZRaOB;%9%{Y?s7(a`a661&ls^m`F*wwCkV9XQ^VXj)|;NW&!iup^#1 z=Z=-xLj)hXc-dk3ijOIYSshPLOyfLy4_wzCxp`yzKoLtB9!yOUC;{t+&r!w)dhRsq zX`zl;3ZRx!7AWOHs=qD+cI)ap^{%RF(bV#5(2V+G?l9V?-*UNpof`P^d8Qb5Q+BBC_#>Lqu%Fd?7`8UsP=Ox#YA@dzo zTON!E;A8-DI@h4ts>y8|8C7KrzdU#a*Zr@4)y(O|lHn}miX~@NGlBqSjDkV`0PELJ z6{13-G?1+Gg=9e6nY~nfefth6N~2EJJb5K1b~;V$OADs?HitPZcXRmuHN6eS{{XbS z5=g#q9#D}Au;bJER~ecw+%qbLJQJ14 z%I6?-Bn`b z>OeUF@JJcp8p}}(i!zCXE>tsyV7_DY!u9#K^UgRNb5~mH%(n7lWih%dC~WO6GmbsE z>-}r0jQN@7)mrFGw+|$u7}w2dW5OMqwzhhGPo++5)JHwkHso8$BKh;Ge(k0M2S4oq z0Oz(UlQdSwGE9ohfu`JWH;nQe^xk0gA+bj4#UHfK_lm5Jk#W{TVeVpJWc1YvW=eKAPJD2#!(7@_%# z9DrDio_z=9P^y0JWR13?uIxs{6Zndq-R>+|&f^@RquQ;svkq`G-?!sj&vq?Uh2Bg? zZK0uP0>mTZ=ir`tcOT@_B#~A$R(DoN)GCDC$N4oBW)G4KvfMf~$p0y5EBBi^Jhi{sZ>@u?asGt(Xk58$quw6B@k}S65%BVzO zvgNoua(ec~XT6y+%Ii6oc|Uc+kf+n3_2z>IodmMWwWf|$`#+in)hm;py?S)6s!g@( zXBnp=Rv^J0zU2>ccPj1L%k}j7dsXXr(m2du86tNcX9agj{{Ytaszs)hiOP-BMH;H6 z6cz&=2Y>OccQGxZNTJq312#!Kj=!J1YTqq~SK%fIAyAhSM0~k`jpHGgKA8su56keT z?2mlS_Dfj{NH$Gz7U@xkKfCNQaC6s=JJc*9Fpxt8eXSpthFzzy9Y#Isc!W_hM&4!X zkblwc6e~ujAzKQ2bsqhDip|Nh%#uoDBoa?-uCf#l8#F}-C5SjH#&CM@amUt{-^`5* zKxU0qPo1?&fu6jcxy~x>v??UbD)Fks%W!45QnH-YiSWO0-3Du?bw@s$9|Rhf5Suo>pHql8Tu zaD1s93aM<3!#v>i6|Fn8VAh1IEy2KG=JMiJ;#mV0UU7lf)YVv)Q6ZjrOxuoLIS>?$ zx^a%9zdpW|sUoy+%#svop34zS5d;++bB;mjo`>_S>vs~ci}!GVg{0jeTw^5QvE=#= zrn{qSGc90G9Qd<4ZQIQ(%jC+yD`1{@&H?H_UiD%dmq@0H-bk?{FPN(<6x=#zj&aD( zy;g;xE#}28W6gF~$d6dz}8XvqNY+ zw78O3<@tPvjv!Q)_wC!)zokr3B%5H2?qub;z)@6gl_YjprP5xFHw0m%Y-C{m8PBn%K)a-93cQWwvq~L_1D{`ddWmx+h2NWTADbbOCvC-4 z1IX@j4+k85Ye}bKVs?AcvsXLgE#2?}83CTI{`BiPJBh9^IjYtfVODnX%binO{>U{<(JFP|n zEv;A0GYHOBMJ*UrAQD(`4o*V#BRJ@4RcM`Mw|kgU;x}I^Hkno0KD;S8Bdw0EV zZL&YIyQ4=B+7tp^r9gLd@9opCtxp`RRU>jR=%h~B&f(jqezjCRt2v3>6BZg)igpYK zBL@V2ztXhZ$(G*LUN@V`ZOW-2QWTTP{#8=3a8i##q$C@kF>Va;xhfVBx;{GO@rDFr z9=Y_XX0=O%GO_*BJ9%zCQU-c=rd&uFVzz;j29{sCTWouIBd&US)mv$M;e{4DLYE%?u>NqYDqRbt;`e64XTEY-X+5Y zQb;NXU8m;yWd1dzXp#$}9pqCg{D{OT&N4or=kln;u3R)|<|yM}p;RjE7#TR=9-myF zOw&oT3*DAp+Sz1DPSJpVSr{(n=f8eCe}zE{+*`5oRV0;Me61M9%y0)|+nTf_g<@~C zDRgziZakiHFnPiE6>s=DoH5@bai7IrthZ>!NzgVUV9pEp0Sx>GX~uIo8=5Z_T$&R zAq#UP(utT2tihxNe4ze>(@#-K7F!BlP~{S0p!~yp19k~MhugJ8B@$0@2xf5%is)v9 z?T{Y5bDyUpnzJc}SmNF$k{NekM&$_@=aGZo_4lX;lF}s6thVbAF``Jth*94-92#xK zjnj*c#lJ1q+9YTo@>V$#CPxLiJm(zb9>>sn)_Ph+a}>@8n9*%lb&xLB_vz{S)yt{m z2+lIzR88|npDQ;w&rhNM02<4+npR-!f-84z&ch%x0pGV%QFek6QRsNS@PmKvB1SFdu>oTZ$1{v5tcIE2hS3DQMOcP<;Xm9(2?$asZ6Fh zT}%lijH73ohH$rf*sK-LM$vsCNwMkk?C6OLLvQHo}tgZ*k>Hz96Gf~MR zoYl81&cMdj@H{{q;X%Px_ZaWZLe|FR86bGzjyBvQDYWh!Z5ZR8xjvstLljX>HO!I* z0};CnhF0x>2Rt65r{h+w5S5kIF`D z!UJHFj1!EJ$9|djrZlky6ET2C6nvHY!2NN8zv1sqNQHApcgpZdDDp!{=TF=T_Cw5iP+o+~JjBiqJ^XU1D-o|!ROMVQL-j*mBvF1ayb(H zoM0;-v?;=#cAuytAp2E@Xye};P)43aguJmn<0JPZ_XnT@jAOoPx)>)L0$~KuBrw4*RO1~Yn%QSIZ zNfDN2`PMg69AohG{OTrR;?Om_+$xm{5>MT@+yfRQ;{!P(j=hdOMK|ogNFF&tJW-#t z0>zd^=m5t6gU(M-F;<9=b3VwXXtRe@E45D<{{TJu(jpb}Pz}Y9>r1g&rBn^KdlZzfETKC7MTxnb89f8~0_Ij(v0b)y20a zVIK}-AG~aq6}(;1oH_Idvvh>a@|K!7S)0gU%NpbW%tsqZIODmfq?Tp00y(~RxQ}xZ zbHUF~&Zz?FFj(Tsi2|ai0abf->^Q4`XP#M|OG!P)nhU&`W@i04q~jZGH!E%+pLN`d zlgJB8xugs-0nhW~el<6m4a`Xu!$3||Zd{PDuS1=nk=Li!jtxh#_657OZ9aJZW{I$5 zIOtC}!QhW$Rv|xWmE$3@(Z*#}V5$Jz6zv>mlg=~Nv9-~vtDuqYjamGIarSwKn$ICs z+IS>3Gm+GL@l#EIB*_vsurg16PkMkyG&^mkh3+L{N1GVj%^zY{ zj(zIOq(W(yI0|{6yN{6|SnxL!C-5EEz#QW|^`{h_j)+PuhfuhZ>_&>kF5?`77T!-n zM;n1q4tw)j3fBudv%(VR${Qn*LgxdvcsqwrU&gZIGo`>rnmxACFlSO2`Gbb}@jA@JZ=e$~I;yrz~Eg2`0Ax09oY8zbpi}WA#7aYg*EKaMtTI4(|dhNb4TfA&(<* z&UpL>;aO}@TzS)lb$HmJj#X{EkhWOV%KwT%%HNnEIOxtobptQR=TA`~oepyorKGuNKqfT)ZI%0{_)C6;a5o<;uvR>0*z z_V1I=wQ5fqM{h1{(mRzgm0d{YrpV~JIQ%EQb+cB-6kefn|r_pG0(jY+GQCb}Z*#cdi-Fj&D! zeo&zGAmE?N{Ax(!nI&!8L^m$R?j=!>an2hY9tA7LBJyLE2KH47Rhd{Q>&QNpWr7zn zMDG4zEpxYqB=Mhoj12qxR*`DNMprU6tn3`k6fn&jM>LWr%*&sbY0t`Xqn}KU^w}BO zc$pK-jws|)B&=DB0f2BigV*pJQ!dK7ECw}>IOW7l7?lyJJY%5b=CoD|NbS#?Be-yP zKbeUnZlvUQ`c|q=HacM@(Mr;0ig(OYD#(C>+$mGgW2hsqKBL}?U{Yd*mULuoxQwY* zCphn(D)0I|#IVaP)zVHv$!QE)dhT`pAo4K@-tHAG!Q_(X^G;uP=3z)nUs_Bwnqo37{I_C^HFDXHlj}tmkPsa z9FEY#GWpPg6f)zE!~@CapXX3*ol@_}ScJtN$&<@0tLcz1c=Yc`rrt2|`Hv&KOR{%R zvPe1xU^oQ##b1fyMr50Lk|jP{MK0A=^dq>(^fl156G<7;uaprGhhH&R%&1v`J+Mb( z`Bd`U$hRhK(%db_0^oeWzwu=Hn@JH#Y=(D| zdE|`C3o3aE0RuTv$>XpjbKG_nJ+n`52$|$EWlDvO!!bPy{yi{i3Dry}cAdz7bW{S$ zN2N>=)u$3eD?2Q56lE$l;1wf0bC7fHJ*%lrN!ZnDhfMK#gzqssu=1l2lBEdwhU|^F zA$Y;hJdAQa*jLV1yGK+Tx7-;3RXpQ43JE>A=hqcZ>E_t-PaLf*@+ev5KkFp!ax;g^S2h0;01OZk+m#N99%Zn|pg*4^k1N z;wH9X0h&_9rt0`T`8nD;0tQYhu*;UZCO5i1De*~F)B&4_{PxQ@z(psot_68Lt@AbJ zr1v%#trT09!bG}JhCTa|523;5uNbcD#nS3&s9l7&)2?HYolxpGh82$-mdL`AIUpXS z0p7TI?#B}-5r{5W2iujBPrQ2Ycq_;CB-Yra%T=@Wyp~*;IQkGsyUdb(rYnq`HN-5+ zpdLaMJceG3-3b{S8pwk2mO(Yfz${~tlsGEP4gmV`lg}TWTXl}w8Kj=#+{D40rLj3I z+>mky%sO$$p{{B%7NK|q2UVX=XLg8N+p5eVPzc@_?M=ksj!5T&iu14UGwNtmO>SJd zCgOHwV5J=-w^U)ZunsexG7qo0sV_ufeD$-qiWv%dk=$zucPE{Uyo9L6(%Xnp_eKFH z9N4i)gpX@1XzI|1SyjUAfT}S(oG}GZ0+zDHIT zol2ECt}ULQJP<~=iw(8iy~{NJ0A;xoMjIy~9D%t{OyG6mwQj7f?wJe-@|c*ofta~w zB%U*q!RR^;J5t?C1FT6>m?18;eorA1YUrubN3v+;klDk=5=lTsa6HFe#~oDh*VDf> z99I{n;7Vl{(a$uE6we8DRtF6qqYNHF{=BkLaMDBmD; zXicF?GfRC+GQch(jy=r8%*Sp)+DAUzb{O`m^I6AlDc=>(p$H{o=+~^L@*^~<&jTK*vIFeuRW+;+B3*viPP-&0Uj_5FF$kv)Z?Kd ziBpPV!^%^+U_`dos2ZvOyZ!v_=9rzz9AOy}+`bt?v0 zZ7sxhw~Hd$mvV|qkXr-;oB}u=qOhA&6Wv_t_m?qAdvbi{f#uyZ6O-KJgO2`{zk22` zI$J23S-#FyJjW$@>yJ-PDqzWM29uXToF@RVBj^mTpgqd3Dx#Bz8ej%%W& zR~Vkv3{0JlPg%8+D*!GGtjf%>q&IsxNE2*u1rLpL1!rx^{$ z-W;Cw4b{%#ujPp|HrXO%r@q*0gUut>cO*Ev{HFy19|F3}lc700p=iB#*#X z0_B{~PBm(B7NEXnjLKJJ*5vtnl&E8ak)DT+D?#-OOPHfRN-6-dN`>q`2!iESK+IGH#|Ir)W4H(T*Ev3^Byh+rQZaFH zHp`Zh*<5*KkGguP>B#r(nu_)drkuLwL2qouE#qa}Q#+3&;{*&9*D& zO%21{#@yTsjK;iRaoFar9{W40Rr<6&)0Y}xwU$_>cvXe0Z92uhWNpKuumGzJ@_6rq z$ThoY(OpEyut2f}Aw!a7QJxs{f)8&004dE08(iI9OLIJHDyk5U!Bv00!G)0*b)VKKXfYm%_YHr+uEwq!|>Dx63wSZ3q?DE>$ zTu0@3#O(`^0W5Kn0`ZTpt#nhSp6Aigs|dwwslwao%GNT=CAbZesTqfU#Rm#-2^jDA zbBc;vi)c*N{(Nb5Zn3*S@_g~e+#{6hw2*P0IIlyxu)Bq9qtj%xw~FoB84c8{0!MC% zv;l#DNEsyc$LZNQFSG#x(y*C10x4%YGf_O0P6i5xcV~%!>%gFD~K8CrwOuKH{GR0SL88`&(JgX&9zo$>Q8n9vYzA~)t7jZ`Brl*)3ng0+a!7N zv99Lis3ddA!Sx2TZsA6hwX_c%wAXDV;zuFcI{>-K!1W~lxv3p2r_))i z%>BCH5>%0r8?HO!Bd{M@=ziR>UP)=F6^>sh3kw&*$s~9K%*O{A$0LfONs!&gdv4Q7 zEDasGieOYsI6p84di_0fT1S+_k-~du&Q|Ix=E6oqqT1!+)5lPFy&FO4&3rH z>+f9cz1P}UskIO^`<5dn)>9ZgcVvN{pmqF>O-Fenww#=x^cb$MJa+TV83IOa#Dy%R zbjj*C&N>R=^#~u#o?Ce?nn`cbMXjujBq+dR2nP++fO?-^)zIpKJBflc(Y3XT`GI2! zOvIcO1P*$4IO~e%FKr{evXahJHhMM8d*p!`qhP*)fefrT!5ob7)`aZF=~_4LO>r=^ z`$3Y*)jX9lHI%mE-t4w;tXObK02K|>pIXVexVx81jUcl&@~+>s8<|I&aUpJ4;~<@< z*m2mJOKW$&Qv{awmUed+D#_$KmS|(i3K@yVJd$(#>H39(n}c&T<<*MD(fLe~2_ca| zAAl?98BoeaQONEA1%BX*J#Sa$SU(rh@V-?W)IiHnMeW5AS2BHM@1FTHZx& zEfUZ!pQecX`$munnEb@P?gK7%e3)OCjFL&g#--0a(W@!1bi|t0#OjjB;NM;Oo=j0f z{{Xvu^=2IBj^E)(vD-_Lai`9<)^`d7F)GH)5b&#zS8EIp{=Gwar2%aDyK6O#nroYv zM^Q66P2PTA9+BIQPE z!(%PY@7Qb`OSika-7?(DBzBX4UPc%PpvDIP0ou0@$vk$_7$Tn4Bq;E)k~xszu0wPn z@znA9-L|s2zi2Jsf-5LqHe1Q>Ez5N|3^A6+agWNiw9f?VnyfN?hQ@n{A-En?`!_h< z!8z(zkD&Z{sKQEGCd?~J3M-kVV~w=Fl`U^R-Iybm63|A=nGVx|z&IJkaBy+?R_(G{ zC8X;ljI-R^mWmshT1IC*Kqn`!I6Py$dj^5~r)UnfoPp=Up~7+MSJ>h~{~qYYi4SW-QoHvOH&VVN_vT+<-E3-%ACEc9V;-^O>I! z_*TyfKz$Q_F5X=Q*zb073X8;|t4iD-h%1%v&JSOubvl25H2YwZ3wS|&s`)@$0Otei-yZc5!a_3K z@hkC`I!l%m^z}a=RWOCxS8i~>OzBcabiGy0CcAG8svj6>w^lgvekuwdk1oC0_m_Ul?7*;eOd z(7_OqxC(=A7t`PIuJ30{m*GBdAH_NIm%8~^-h2b0e#tssmo)L+>Tz6M#Sx19MhuG_ z-ipKTt`FWEe_ocu_E+%6oo*ytGt0I)yx74|!@dSM#eKhPpu0*M6%iJ3xTxK`)MWMT zTDLkyxV7^n4#DLL`$yd;{{XH0=;exfBf_3-n%0-SHtu|FY5Ozy40%#rT9#Lh*UUsJ z9!%sCGD!5mK8Lk+Yw%ma`g}`mZ((TuSU2Xc}LEHTolU1;kwOZH}nG$$-uh0mb=l^oN#tYL_oQj>pq;I>}~yeDf6 zl1ZgN?*Jz9WB?$HHyp-;>ETnI?k7LhEU9BtVZkc;jp--HdMMgU4TA zY@Uc!lzN$}61utM)}8~=BX?*8je`YcH@8p|9BM`za8Z(^6OcNL)i>~Wg>7P+?D}4Z zcRF1UBJ)hQWmQwg)eXp8_1(`Ma4Xql(&4d*0Jbf0=QA8nn9L;La6urBNy+CUf!4F` zH2Z5$I(g!?SR`Y<=6M->v(tj44*B`L1!*a_)rsMv<*Gcs4+vO*MZKk$&l7p1ZB-`+ zKAAjYALCK2lGy2RZnTMQ?CzCIEt)Kf$DC&wVTA9;Ugw`rwA18kxAUQs%C*|yLfcr! z(-l57(qoe9H z-$Zd1`W2#^!#X(t(#kkq-($-ypm!36;ekAZj_ZTL9nE)A zTQFHsAXoVWf_Gj^bSk*xo)0+s)b^H9M(YI9{{W@oe3;o3t1-_f{NVHHR}^VW2MTwQ z=l1#>3wIO}GRp9#=9I=TTb?@l^{Ne_EzQKjvPB)L+FM)3L3{#&;l?gNazGA4_`3;lpjEZX!VrpR%OH+xTMwU6PElf!Q z#|NBTuJ4;U>5ha`27s)h;@UPc?>pt)`?d@*v<|!v!=J5o=EuprE(e<%MpVqvva2r~ zXOZ5lPK_F^lyEJk(5o750ayP3t%`BPyBxJL=ghP`>fgh$D!d}z3rQ8j`LHP-b71oP z;GS{x1HD-qL0fdULZ^mgD4??YXFO!~KK1A)Ob;yf(#0LT(K79xIo3v#9_mVveT`<# z3OIo+Hp4UdpS-zTC?IE$Nc_5Lnz8R?u?sNGw{88ha&kq6o(EXunSU;v!~B%Gh1?OA%2 zg8ix>o2}GJ0H0`VEvHj9$y`JlT9LrJFl@N4JE@84BzaF7ggR zKQ28wRyF5_{&|)=J6UCEHk);TyGS#Q+zx)V?Ee7SH&*L&3J16{l@Tf+X&H&n8TCKs z98@Ap_-FFI$$h3=#{)+PnE(3ld%U+kewX1lh8V$c z+J2c7g}2mi?nTKJq|Dl9Cojv?=99p zv;C$Mb#jvu@(@cod;^?wj{g9yT#H6YOwz`YK{N!b!y6V@*QnZmyOWIbnzsg-jw6L~ zxqMJQN7lXu+v*mw!(y>oUb&5=^VF42FiFQaQNGp-Y)1>J z+ZhO?;4cR!r#1Q{BY4t5B$2f9sEL|H7!r0Q4!!Fi`wfHbi*q!t%@naV(z!jc&*53L zl$M9hV)#oal%AZY=k4FXZC>9`lG5tf-dvcOm@|cEWgm4@fxsY>?mcVI?7j|ouS}L( zJADPBx0G`PMOjiYjlU@6aDS(*ex@G}dG{8YjMng7UhZ^hnl@{QVL09M6M(LE=dMbO z_N!WkhYag0LtwI8x60SZp;|q?J%~NX=Q#JMl(~-{rvzc-pDfxxFlG3Es+)4R)(dGR zunO~CW;Ja0CkLSP9ffor7VvfEjPYtx+qhYBgi6`l{^;%W`d8mmX%R-IHizvyfse|4 zvM5}G^5h+?4;ch^6`enV>~EMr@p%iuAVdQCoS$AXSw{^CGmHI7`n0*Pc8{ImiCy5i zDk1?F%V4{9x3AK>C?ycf3{L@Iu@5R_A%u!S01?IrZ_tYG?)(91Fl~&|E2|~Es7P4Y z9^=1pjye3R0$&YZ+UqfF63-W%8jE#7CR?CfbDnts?LZR0=QYxyIGN8Ymp8n&Eyr$S zf0pJOc(v=v1(nsf_CCE2bDGP8NsiXe zOI3wqON*v&oyj|iIVaoy0IiCvsX*|lw-!@^IH_>yNL$ zy?GX&d*>J5xgsAavw^O6jaMkKGrzj1r+h#z|af2dDYPZ45(=tj`X% zNgw4Yw}R~TYip?FvWQ5~$+klnEMz?yyPOU)ABhOVpDWHq$~SvJyhmCzj3|ka_HSgYR1Kq>G zcI?2WE^A>-lkLcyw9Dhg>L!9>+2i$&ja;qAj61gz1iK2Org?=7e_-jgv z#?lKrSS5@GirPHKjt8J8rv&qide%>fehYY4#gastorGG7i+M2R4%8sz0i0m&_s<6& zmG3b^?$~QoD(u_$at=5IVD$uNpUS#a(QS)c7!LSlKffgWs(pAF;QqCQYPv7o(DP?X zE~A~bXXd`M`ypttU0vPVx7l2L$g@edHaYcS=z5;GubO;u`y=?0G}I*1twfRwt+9~m z=u{p^U`Qt&G1k9q&X6u-xQxJE2|MJKLn~mMan5u86_+=Ml4-xQg}ipQ(#WCSXpfe; z{w#n_2e3SGT~Wl)s{Qzy&~+))-Jj2;$Lz!6ONnE*iYK1l?nd+0+$%{Vf>n#)PN5{$tAOp^SKIXr1f8i3aA&lB}oHNGEtYM8? zYXWlH!1#&lT6l(vdZzc=X0DsatLM57~_sX z=Q;aaKk^YAUM`yVozLd$#b2>!jC7>}(%Z~g?Nwk~dq$1p1oM{39D+Il(DTx`1^toy zTqJm=vbv9cBUW@Qp>x+GC3Ee~e@}AwF2Z$Hynr*Jj%8iU%suhXy+d*E+ehoPaM(y%R4?oezjJAX#QyQU)dwZn#`BFP0pM43FqDCeV*W$*_Y)T zSPZcPkZ?Y{n&_?n0A#<38g=1<+QQ@`K+7}zoV3hxF|=bG^OM)79c%hNu<#CxWpY|e zD=6iH-M-AhLoAbLr*Oj=IO&1!OLO5%dBiayW#SB?K;W!uNn#Y9S0_9U{^o^C0WXOc z492A%r{c%MKiQ7%Z9M6oDbTeYD^a&!-i=Z<+{%9L7qB4bC)8IN;{O1FSH2JNG{Z~M zird+yB{r6UQ9_aiLX2^b^P2s}Zvp7fc9N}{&Zr47U6zv)fy9~Pkl!+n#~H{KEdB(w z)Ph}4Wdw%PY?m_05Ma0?h8V*s>Cd;VTBnxB?5hc8bsb)7UgzPJ=Yg-`vbVXpg5aVe zvzZSl*ypAO-%R?|J70&IrNb@7o|kui%2#c|kW~peUC7*!Ivjd*ui9Nh;I@Z#Ii2)@ zcB{FkjyrICwCR!n04ZVz*Y(qb;Xj8hH2(l59V*umpxqYGzNeAEtY)yC6^s7S<>-&b znEnoUhR7|%HkXWVcP+xl6EdWobDo1Ijw_wI_-W!NmU485OhypH1PRdXG@d04{6LvB@W za1UHy^*r{hl`JcJ{scVIq4));cr#bFhW5pvmNvaVK0#a~{otprM_=vo71v31bu3r# zi*SUpsv<@64VYZ;Fmr%&)Si2q^h=+GekRZ@lE+qfAevt?cy1?+WMHKH#ibxV0Rsz= zIXDA6`j3PD6y4u7{lu|PsCjm=yF>sB8mKq`bQvc(>Phc`Q5-bx;*qk)QE2(CMVVJ$ z?Ky5=3MIL_wp2Tm9$8f5ryLq>ymQ{SpA&teD0)pEV^&;t3<1dZ`h9&<#~%o_$GX0P z*GIe4^u0iCkztA8m_}D8WAMs(;ep8Diqp{k5%`YhMu&ViFv{>9#wdcSs2B^31Cx$P z)&akK)foSx_2w|qz84PM4bBDl3aYlaP!V5$M&AFXpRXm_w&K>A*n zd8V{+s=CE+S}`K$4iF4=IRNJzX1S+EaF)WQILazq!)@M6pzj*oDk8A94KK^Q9;9=T zw>)w8f$dk~l3_R5*!eL-Y;p+z1jgby?d|Vgf#E+0T-`K+Nu||hxrDXGsc|8aNv@83 z#+2ZG@HRtW0g!R)QEOfZ)zu`w8dc1&Y3(F;H>nZw<6Z-0x*l*aJLB55g$X68H7i~2 zaVc>X#4-q`Fxy_*GOIkESll_n9_JQ$N&TtU`|2*025zb*!(J!Q@EbfVog7rhQuVQkM5C!MVL+30GCxS`VDC0yK z+{Lf~?dnPC$gaajvX<^Eo2#`^6j7^UX25Lr2N>iW^Iu6?e$1~W&D$G+1XnV%T}0N! z*sok?BLJKa)3C2=@Q1>i4K4_6rMI$~R#@X$WVczAs-M2Vj-ajp!S$|{gK7K1t(f7X zA9daO9|+v&x0Asf15cP*LpWI79Pbb5fz@z%9k{KlZx8BzbW^p8Y)JgORo+-__XK*5 zmG?dG!u>7UNo}Ag@knGvZfZIA(E=L*hAfO-9-w3~>JdrI^&Zt8f=R2ch?{VVJOtHVzI{ zgTd#oZg?24z9jHgoQ?&im2GQ%J1?EATZUVSqvz#pv0N29cmUvibInKacFsh;p7MKX zjl;B&Tg3rcq2q7NPh8+&cIVc*B}y$?=I=G7HEAQ_bkQzs*~QPB8MU00TO?bk*|Wl& zpP519Jd9-WD_T2cwvifZDI`~A4Bm2uQh5h&4Z#`6$j&S3JAa24Hn%@uy|p&;TB5Xv z?8nZyg@#kF3R^07V;gdD$Th`y$H4ypVvT>ZV$-M8<&-PLZ`GP0$DfcL+;zq=&~PgW zQE6^))UQsYm5&j=2I^@{Wl}Uyts}#=TWH5_Gt(#k0M}Hs%ZNak7^j;SCfy`wX>Nd! zMjO(*5#e1*;z=#wj^Ub8-?|*_Zik$AIsEH#^TIl{jCRp#(fJmwY_Y=~#DJ_Z{ooV~ zg;pnVBf0mid0I!OhKv=pICgC|X&}3et|C}AsftB;5Xeu??8kx07*W6-dSvZdTt+WW z=Z%@nv8#YLGLz3dj2~}G#ODyh+ z$db0x3i3*iO!eevCa|oIs)<|3_6cp_wbM4*%Iy`vQ>a?P+oO}q&e8`!!*dP8oDwS< z%2{HXXp-92J6U5=FC-^$ApO8PZ8_wgeo@ag#mC|cQKmq66JB7Mk|JazoP5|B-~cju zV!90t-ztX2W9&M@~sR_Q>=V!6xMQBAgUa=m>;CER0JS<1IXi*-t}` zy?D)J2%}*fGs@+qn7PX_Tn?Od;;z_UB$8^&B-0m(5;$zYUoE#Bll|&7`a{VP%^U1FQfw|K)_FP99g3o`;#la2^rI0ukA)~1~uot>bCp)*Ra<}pGG z0rm9f6zglrrj`~lB)gTG8(GE`S@NKqV3NH+JY;m_*JOR;$GdVkrm$QAReizF8ld2aBsyLB7R ze_qv%cWPp|u#g2{w(6*3a9GAN4(xr>aCkk4J?d)HiP=rJq2kR1sdqKLRg>(&WRX`J zPEXI!oLef3sQ!(lg1+WC4{y>Q79J zkMe36G|2qIus+m=DAqT38-{w|4#%(KUSj?wn%dF`AP;jL#NWL(&BdCj$uGOAlk#zs zmK~~Lt!ffHx0dm&R)QkTBVek;pI%Nt9qXc&Dlt|&X~tGa^qVa*DP|8NLuziX0#0R( zvKW8^9iW^JIT^+|r`<;dp}A|wpq@oR6mw*TU=QBwkJIa19iNJCZdTgmw?x*1YsSsP zE*l_Y>Q7Go^?m1>?ps%y;1p&eI6*wCb=-6L53N+IMe1qn+d5-!1di6wT2Fd6ZJ64T zBBdVW<6 z#jVBqLj-a>cUFoSnmm$ZfMxsV;i8@U^2zI;{(_HMPT0u zr;kNB6!~^S`0m;uDYhwQZQnpA* zR2H!!e*LE-ce&3@6UeQp{_y9iB$md8mufDS<>Q7sh~vv7awrVVj1J?UVsZFpwk~w} zEqu6a6)qMSmO~MMI7V(mKXSW(7(LIubNVCP*qN>w4bPqz%C$fgg~{A=&u)YD=DN5c z`)tfoD`^#qps@`dn#XRd*@qi|85sn#9{mqoX~r=yg0m}H>b9r-CsMVxnnX>JJof1) zm(TFz9i*IcFnF%FLA`=Mwp_AX$c#ALKq|Q71JLy~&06U;mzK>EvWTFCw;{=8Z1Md+ zTJxvA)O1Z&;?=bKi>rATk|$Wg#s^YcvEXnCLFu@HLJ1M$fZKA zMm@8Rwber{z2wUr%MzGOhE`?(73_H92d!`#73`DwGf!#+azg6XWXJkcj0=f7SE^!4_p;`|PZP>XgqjMs9UdVKn8h@`Q23QHy< zU8Rt7$qVoGuFFf7JBuk6M7mj~2Xu$9+BS{21RV7w^gTGPw&LEx?%>>72Z>>cg{-Fw zB7z2fZoPrUc^&StK9#7;6p~LglU+1y(l}`*ayJ&-dY%vELxQG`YLZe~mF}(8p8T0_ z?QaZBHrVA@sW|(}X?b&Dc#KuI%IsMtMVp+F&Orw!*1g&bM%6UYdSI5~ z$4s_XmF;a6q*(LLdItH9Fi%tOTpiYlZqr`1qko~0#==X8Oma!wZeDhrbs6Ki zj*4wtVAG~E+s$lUf{UM?GR3zpGn4uZR_}(K+v<~}eVkdaR(ND~49B3x1~LiVmd8W% zu0uq!ycb?2-oKZ(twX1Hy52`Y1V`-VGl`iQNl#L( z)6*5iSn3w-ZFHAY2Ubs-BPb0UW1dH2>H5>GZA>%TNYKitj8-=T4N2giG?mm$sSi}7{87NSY>QRvO?(lQAr-h3^CaIcdo_+#Nx_X<#vkS&Usec;0$!n z1Fs*M6weA+$!!cVOvqz`GNL&K{{Sqh;Dha2+S4_ItK3` z>&F;9N3~#FY8J9WVw&peSzhI2XrNc0?q$g<8v0e+#XZSYk$k`kO|gf}I6pT}PCmVAIi#6yB)Mr8LaZAPhYZ>1 zbC7fBYf0^x+RNmuX}U6~!f>pup1XRm#(HD5ar`@}1S zkhFIjipCYV!5w?&oIsgtZPI&^ogI4flvk4k7QWB+| z8H(f{=f40N;Po2=Wa4{Zj|@qlDFBe~UZ4(yb>P+&DD!nTr6mxy@ocvakljZWnVEM> z3}NJq{{XVAdEn!d)B|3PVd6K9t?l4vNw;p4sLHYqy!JoO@XdLAHn3X6v$S*GOL1_m z9l6`JQNH#G}{`LD9Gs}8)PhI z?SgTP4xIY>inQ*DO5q5RAo6^j&etEl^GO(AUYWV5)qglL*!_J$-wCJxKJbS0+)r zJApijZyGa8F75Hb4&r>ZEu0SEXD9JKwV5Oa7kOcTJ8Ut7b8rz?KYI`QjC&5%%#Bui zE0krHZO|hrmI;{|18_mdP|8Rnzdp5nwckBu68`;B1aK_iv504J3!XsFJa;G7uG*SY zh2F-Cx?J7)*OJ8_*zHs}w25~!BH&{f3{E+2r>W$c%8ucublEd(S&Wexp&?n0ak+Y* zaB5q))?D2}M8Lwkw!20F$0Lw3M@)3j=Txt3t{}I!lGZJvSey5cz*&7g_~-oQp~>AH zQi@2~wY?Eb9PK1tbW=8Ca0F#@oB_`xo(^-G*pl|f_`I1`TX+jQJeyQ6y?I^Jxw?;g zumpiA0G+M>0PDqCw3(uu81~4fQkf6N2RS{xsJl37(oR=BOYC-+DHY6%43nY~OC}YM zKzRNk!OyKjBx`KQVsO&3FU)!Yo@*+`?qq@|pL5&qDv}@yyO*lxo`V@4{`IdNz%mAi z?r$uZlWLVx4}5|T(9wNLi{(KGAjslC%GlUKZC$@ioK(>nCU3KqK?GP>_x#GI=sRbc zp&6R$b%Rf}p6=xQvBoXN>4tI+#m*a!i|y%24b(aFQ`HJy z@b-!}Tb79~5=3H~@1$uIzj74d1?M;&urtL|Hg2;-!Z8Z0AxhvB+xT|>0P9xW-k>FE z=aS+}h4bVM=D3iqJr8l;KJ`*vP9+6Fb|}&Bf*b~5Mn_&b2ZQfJMZsLDEK~W8vIH^6 zK0-$2R$kqzo2H`^23S|@_Y*R;(*|gFW0hWnI+g^Jk;to3Ncov2gv+(p$y6j0Aq4u4 zpXaSul0g!yNg&xWGKkqXMv@PiSmz!1;OF$AY;^lM5yfmgfgDjOx!N$###`I@){V9q z0g(fFYE*! zkU_@Q1x`mCj{dbX({ZTs$mX>m-(`8RE3`7mVnQ~v5H^Z=#-~oOAvryB3jdplNP5G>lkB=3ofd(0_$iw$q`xn5!6(ge<_%AV5_?BmzhT zoL~XTI0Kvtbmq}q>#5DWt#vGSUPOr$3?Y$WkOx?fPZ>S&*W6~DurfO|D<#dEAHM1Y zjD1M;`d2{(j4S6A2x9;xFOP#z#(_J5?LT09(dlbd8Sbz(xbF9e%y*ttlB-n(WPM zG<%m0ga+H}a0j71d8j8gQ`?9f#?wd#krw{40iUVB&-18paG zqe~6`Y+g)$QWj+gLdU zgb4FST^<$?Ibs7ha6QLg#-DAa18+Ck+Tl&E*`<>unl#)7TXt}ykU90h#}#cMMmmG)J-w>-MiXtl8B*HerpPYs5~AUD7Gc_~Mf;VKIHM$l457KnInI9? zM3liJz@VvU2bUrOpp%@Beh(t4OeM39R)$YAXbmHfdCzWrGHEo1qcZ%_EzPr)D!b$P zTOC`_R|z$$%I_uD+BcToRvV(Rtb>eWoxqIs!RED6OQP1ncW<6~Jh+sdv4d6Tf=6Qv zlZi?nlv_l@E!be=kRhqjuPmB>wp6i%Ufx4J;XM45iLFS{ER!D7`o&hpA{mV}B1yD%N&wLUw~7eS zn6kpI%Osv?BcDO_9OTfQ%xx%{vS|%(1ajO*b!=l+e3%mNEc29dm=ggIBe)1)Fq<+OMr!h8o=gJbL6XKdA#grj+5C9= zR81Vww6dclknP=q+jg!i=z3Fg3PK( zI33U9S)yBL(2nIMkIYXnLabR!rq&~#Nar6zRV9X1Os&I*xj-FN%Ob8%Zr|66nV5Z> z62Q?rN>p3f+!7UYj;uLcdh=1Uc~E&#^-^|xxdZF;sh*`%Y@z1}9(1_3u@@m!L9=v) zTe?PaLoa-u%hro4%W(wgvTSB!=IP$E7ii#7}O~ENZAnl##9pIO@Zv zr~}%89FxE<$Cg-TkVz zp?Bv_@J`Q!f=!Yx6@q<7BRzWm04imr!$B9GE+Zz;D?<{*7_6E3x91_0jslT^&s^3+ zU&E@k&Dls2{@Ultnd7z)t7L8%Q^CL>61-%3R7rspma89`%`VbtK9>(#)f7;HMx}C2oeasOp7zWFA@=ibo7Pvk%PMPZ$G?_3!Ic zuC%3_Y{}*|t+Qp6uGtKJr_-923#%)TS{8ez1guRIoOytdLB?~AMm>I%*ynl0<4H6O z6fc(0qXx%)`8XsWKtCSN%0{w{+aQ&b5B7UQ7=eO@UziBa21)whaqUty!mDCg#>9Z( z3V;-Wk508)&V(?;$V*9uA%iOspTPI1OGX;!5tdAeCyfa?JGO=+o;kJ)md8~Pgg1KTzt?pvnvX)#jhEi3w zk&j{xRcn+s!^@7zp5E<>HQd5E91)SSGs}>wNdqJ4nrhq?%w`bpG@EwE(|1A#9Ytk4 z%M^1T^|MH#G>qGMg;c(B4i4UNlju%PGo2H=Ek!0ec`f3GNMn{3y4ob3ICI2jILN@p zf6q!G)GbRye1(f~3mO7;?FXh0rE|+Z$**O10(6usN1j?gU!ghts##J6P4){R3Qp#f z?j?_09-{}GdVMNoC3Cvyy*Z0~@hOTnc^k`_&oQCu0qeJ+{3?#4Dzb>8ifeX(7jY7W z5(0kr2R`*y=Hl8o;Fd|QL&&Fkh`)AMqkQ?`=NK5|eJZ}>l_PtC&hZCW)UezWsRKT^ z&;I~kmo?6LG^A@wE+9*WVKv9u{JWVIz%qIOItDr9_pI}2aSVw&yvnI6moiFZQOE0t%uNE1IDwUz^Yb?!d$$&=Up6+AX*kYsa7Rqjn-=QQz&Os)2D2B3x4 z>{ijnM3P8xmBsTy->HM_wC_kUuVTS>!2n;|7sj=YZJImhQ&^F^~dzJ&L) z%$8H^h-K7a_Y&M3@;MkF)-CPA#BDr*6mgq&>xK)Qj%dT>hj9Gv;CE$;2^BNsTD0-+dZjyif%hUYgcaz#xuQPeGNBDq9)B$;E` zYp|A)w{+Tib?8S*?`&?TxLdC=aFU>JnnAfpIs7~K^shHdwzr-;Td3ufs+g;#+(H|b zl4)&cm0^s-72t;JwP1?)}YibmSnPYc-C8I z-mnQ7WD5Lld~j6q06o<7;MOia`YM#!YGWa|fU~!gZxd`~#z7fA-G8a4w2=JK%@}Bk zuik|15+9iIMi1fNH4=I8h~56nJf3R0y}X7+SV`k}AYkNU9D~8F>24XIiaW@ywITb> z(B3l=ndCPFa1S77fl6!!_00EJ9_^BkyG9l^5bxV0-yyb2?2i`@y%w=T4{~K+NIUYf6GLis~n6UyUTqK zUOxghOp9|H$#EU56J}W^G9t9f6+ry+)ML`KUgk;G(7Tdmbp@VMSxL|0Mgi$lX>*UV zTh9o$V3Xt-NRXEq!uf0nU@&u@J9nwsqZ{Q|*Ai`9d0=GvjyUJjwQsS{D@UN)TbN8u zadBrAWW0=(jgL+N2O#s;uhOQSBrhnDe4@Y+8BzcTp8WLbSy!_8GKl0{?eiws zBvk@IkDZV40J*@=Q=emP8W`Z7gyQdE=3fPfTK!*^o3Egm){aS_ioP z)OA?xVMFE_FgES=C%69qUad=ID*3Rh$gcuy5wHSH!>)Y}c*RtR%ml87%aAxo+!6-Q z{{T@vD_|sXK*TGzOgSdu1%z?S~vG*${?nEa}%oRD+VuR~hb5Tqw;awWl*OhFM~ zWI5n)Gmpl!Q%dHtae&3RlG#=}NaAOXM$Ef`+=O%kgX>oaM3Nh!13c2iE#iSiQgcRMEvWQQR_#AuA+pGVnlPNF*F|Ca<)T$0Oadw2L}OXSbK;B3Ap% zTdDN}woh6d?#$G=iaLaX8+Uii?$iGOqelegRxmI_NQ7aOjlckU;P%0&v)w#b2Id=5 zSgy;PXiQ~e#y)Hu9F7S9XTMspH1OR-*eU_YaIc@6y;j=Oz$8N)acpJs40&Kzq0VuG z+r34|aM0yu2?f-VX^5*eykn{ch!N8u@P3r(yohZicR?7qc*Mvg`OA9a`=_3JahkLH z)cZ`<@H4yletIv;po5Lg)28fX`s2M%sakDT20Y4&Hm(Li_xkfj?3*-Hwv0=5t8pLh zHm~n@9LTx%;2PPpvQs4BIol{zJ7NsVx$T~Zflz5kZefpXeoL6YcqbcGSXPz2vMNa~ z@=Ls6D3GofuHp{^Cp|qXlw)I9&y>@%(3UwOXw;7)R)sF)AG~F5NYA0iPMmSly&}m@ zn#l=)0*3REWPw&TBd+2`8;$~;_o@~?YS^q#4(~2V=JQNtnOI~3PeGDvFT{GZs{%y^ z9#_J-iATx_11IzU06D9Rk|K4S?qF-zzILf@k;lFzPq^d(8nbi$IPP&%-L$r`<^vqj zUP&otCd)Fy-{)2Fll#}gKOia#l+khM#`;1`yJu9xTA80YX&i6qHWJuI9 znKSb4=vU^)=bReBrgTwz6>ee@c?jlrVweTV3I=*)oCEFks~Tiq+1Ft%LP$Rr=AIO3}6S`?5qy~U z1Q14g=dChGB2yHxO*70De%l7o8Qa&6PDU_uj->rd1>;4CWr(zfRW1UblpnfIGDyJd z{{ZW%QBhhNxXDD^)7T@%w?0@XLqu)JRb|Ho!RK%sW4~VYb*(>lHQY}Vv5;(S#Imk> zcC3jaEg79-@|tBNN5~4<=sM(M9M#xKiQmoJ8rhM!nE_UB)G)y7$mv?BBaU)+Ijv<3 z*0Nr$&yy5jiO%ns73y+E05~J_`qMPa%O@fho>O#@Wp?1U)7bw2vd4q}0M@O0+mjl` zi5Pgk(YVG`FeHLOApPO($miVF91w$XJ3$aLTfw=$U>k0E8ST&Xr6}v5oYO~CW=U=B z9$1zMVTD#$QOm}so&h+>$>5RrS3h%WX@4qOrM}k=efPp@oo>OJczNyQTw^DvSTe{&i~Fsk7#w8eit6-x+dI2&`0|3@;VrhKd0;$h*}z^&+IakjrfXluei@4H-E9r5 zT3f0KEv;dVmuzQmLP;TU&=c#9wdPXKK9@bi2)xI)wOx_Ka`G@cRaH+J?~{+MbW+tj zlAQVcj;SplWQx)m;gV@Q^mFql&&$R!&phX~HhHx8<+Qc9k~n6$k8Qe#^4Nvs06UN} zPCW^#wq7B*lGMj@6v8Pc5=m^S8nZF$&nF`o88{g}rm;1-qm|NFp5_)27DOxyDw25b z?ms$hYIVZ2?PI0Bw!0I+7UY=O+DM}xb$fH$xT*%?;?m-4nGsz))(ayr-6D>p@$#JK zj(d9Ivvl2dX;aB*qm2=jS!Rf|jJ$o*jydn_N7u5m(xJS8p!-lUH<;0xkjP{_vwXyi z5J)1H93*U9gYCTbJYI;jZT6n zZ6m$3y0wPt?UAjcxlc7>3xo5-au^(*4o@9Dc_$uYty4uEcgWPN?%^FZv5uWH(QO(Qq}&RJoGM%>K(NgX}TJ9Ft=HSpBxZjW;-#Z<#o z(dc;It!S5bc9Tvo5=ioq;Ym@E&QGTw=M}|ix;4yqa@PcV7I0$DiWah{y@?eAW9e-zfTM{x{zytuhl$hR^o1CF>E z#zszm9+km}!Nb{~f0gHM2@zR%WKSA>o=b$0A@d}#F%Sfsi6e11U_syvV!B%xQ!e)w z8|GIL`D+Q@82k6mYgXP%o4H{C%q~_h-rN~?24Z>v$>XWdsQ0I8H|=3~%U+8$UzJvzJ!U{ZF30An2`gu9bpM^gEdqV3JFA zkR}clofkO9dFO%NvadWjZEYkG-K%dxB#9Ugow1w@_34~?WY?tJ+D&g>v4t-no=-jFFnK^Rj%;LSBxQRZ<2m-K7Fw+L`o)Ev&AJ^kPiZ{Fx4iOYnK@&Z zWg%O#j1kiSlU-h+q})jqQzUXK1&=EvXL9ZwamQbJ!YaB&#j{=7B#ax(J4gz8V?Mkd z^%XJljkVDCDA&VEFHUJ4UY%!es>d0)ww8NIKYt;T4U${5XDH9R9>dosrF44sm2YFD zORFq!G>>EEK$1ooRk5{v#pn+ob%sw;Ii^M8JvwB!lgm>is%9}p${JM}ED1aUN|A&8 zYoFA-Lv`X!7gM&1JB75ppUiNU?6a(ipS;|u&h7!{udfp;9#i1! zOIv+L7HhZrLz!CUFD!Xw*!2e)Bo3dC70P@-w$%=`51p<-r07d`BRo*)s`6bn!UD8~ z#?VgQfbb3mO?J0P`gQbI=@Gj&u}7HTfGYIv0084~$s>|;?_5r)eJ;1CBHmleEKG`6 z!EVhOs5!>$U@+)O>x%L@=Z2=#k@gCQHDy!mrQ~k>E0#arSi~cc{`2hiJBUREn>%s% zupPcKhXecKoa6?Gs12(X~~&w$!J8w72e~byX3A*kBGl z{p;$V2x_-7S*g38^6X_HFh>`d(1Lm>P)^*P+3k`}F6dS z!ty%aY0GO7fQC|JjaaWF@OvEhAJ)0s&jd-MjaFNDuVb~kQ4QSI>_W2=IOCjw+;koI zuTJpRuIZ^)k>m1NKhLPKl%*Anx zpFzMQ)1Q;fGfFUyr{=hv=P<+KUo*0Q*K^_j0Ek*7E%qHQ>rb|p8&zeJQx}*)4Y)Zu zBZGhn@xVUyjx9=pzSg*=F-RMpTo^w&fCK_FkfD2mo2ccwGk{*E(UVs^4Y<_ z&u*C`Jwet5^pl-F26XaSqme*pS-2R-b{OOlj(gY7pJtK^O+Gok+i_xTm`?TuW04qr z)g5veb#9|4gVwqq1j&DCbdbS_R^fv_@N!s={rv~vE2=o2X*GYu{!-4ckgJKSTKe6a z3@)UT$i0df{{Vb39n;~Ymv%)3lDkAfN6Le)c&PQ@by<63EueE5_8i5x{584@^^B_?i zk|+fH-AP_J?YrK*T9j(3y&uf@%uL*rPBX%gvAEQyU?E`~YExiURT%(*&>Rj=dcS|G zt(W@unpqRf+iI5V6*lt4q{hMsWx^hKC+TlO5;fT+OtESX`(-?|l5WZFa!2*|tsDDA zn#STuLPv1YP34wfGiv_;4&~1yILQA18snu#E|ZL2r^aWpoTSey@}$+SCrc<}hSE?B zi5#VtMmvsJXYUM=#~-a~-gp-J9Xi^1WDOm%Ja)Gzgsf`ZvgGspT!HF+YPW?iY_$Di z>q@zT>Q|Oxz$!aLpq?0i{{Kk3I%QTQm=gCP<*w?5B9X*(@K8l5N3 z@An@8UNeP9*zhY$Q)_j2ZPdFUWtuS<0JcfW_3TF@-mZ9mSsElW`8LzVG}6e|7ZY8X zBWTY&ZW&w-PCrMP~753Wb+;-WjlKSK*&Cw_^(s(wyCdAq1;%(X{N&v^4bk#+({+Wm>)E4 z2?8*rk_iBw1_;R&Y3i-TMNLIxA+8p@z$xGad zz0abw&kf(j1hT;El$lI|Jduy5^RFk?TzH1=JIFrHw-Zd84Z4Lfs0Y&n2kD%F z+po@M)F@GcQIXw-sR+?rvefqL(%Oxdj|3@h%X=Q#e#(VgYOv%sK2{h5aKZe}bv17f zz4gVsaxJyQ>pBJss|b!X9k!2|wv3W_W63<$1-7?!q*!S7(pcEa65UkZUS1exLzD8t z7a)fjEW~7Bdh_3ST4?pnMr*jGS#G29_uAWl%A~dn6V7m>AJ3(H_9B%!tKRBG=+UTy(7L#hTD$Yts6yrYr_0D`Yxth(^_GL>}ifFq+NP4faWai7cl z=DhmYcvPhMT1T}i&KQLr$F_M9-Q0g?MTu@Aw+RiwO@I!$!hk>ToOP~u#M&!MZzr1! zX5u2t6UGY-xb8jvwb^)O?Jgmf`r=iJ?pb`cN0*e3KYKke**GBQgTU^(T z7YrI5+%#*BcVLcl$6tE+s`wS`9Hgv!RG}HJV^hHQ7Mf>=%!veW#VR&dV9LtMdMN41 z=bu6AT}GXuKBseYsEH%;V|HlJg09h(<0EnGNyj}afV_(0J2+k25X%N06n&*meR}lt zuUhcS+UUL(o@BGsCAVxO*YU~bZDX8d5?G9oILK3BmU~cJ`=_4p44! zms7J1k5wwD-0@v5#%a7@@?Hq8R%JwKmhGm3J*1GpEsa4-);p8(`Q8^2o3xVnd9$|eZ!GNg`4ZOR5o&l_8De zX>a6t5w7P^q)G8=?rWVD2-<{6C)$=p`Pk=z4zT(zLtlC}X#=nns3LWSh;K zQCWuKN!zft^~O4M!5HHe+x$V+?sY8|dA8i#G}jBcp^-!|!_y=ap12tq>OQsRT3ztd zo(V+K$cnu0$z~+=KZQI#PNR$1`&_EMML|a9kh+{Sf7yApThS&ZmfWdUBZiSd4cKIL z?e9}-m(f9{3nL8XJD{yS!_GGvbHrkx?V%5bbp_J( zJxhGCv_o@5B%f-=p#02RkU$+iool!v?px?)d1HA>IE|7vSrJblbHT{;^!F9y{u#Z# z(tJl}C6q|(MtywkNCi#hCXqmn-?Ec#-`R^k~la$KG^ zuozL)6*=lF>oD{^tQ2g2NM(_H(RR?`{wHdWH`#u}ei~Vzjzi=s$GKz9_22*-1D@xT z*OSh8UiRksw#z%C!Z$@6uor28#?%A&NY3oH7zeq*%kjh#+1*PSuxqPXW--Tm9r~fQ z1ThC;<&^RXUO_9^)jtF3X=5`YUBPs05;-GVU<8dLt{5{M7RUer&>Wumt+040tXpkp ze#L>o#yL`P)%=eC09iLaAGVTPJ2-VVIeUh@yJ+K$NI8AOsa~qR3BboR-4AWt+CzEh zrdQiEazq+Q9ryu2Bj(OI{5#V4n(oh1u$CJ}g6K-ow8+j#R>vbgs@=UuUNcm*Jw01V zSzO+}qYcSqb+>6F#~ix@^5C8`!RMwc>nX#PSsvzD2z^uE(Vl~Sd1+y1C5wV3WeABV z3J+3Faxim_0RC7$U!&bl`nelf5-}i&8L(Ri8RH|6az9#~W&3uga`zX1W)?euvuI4s zG3@6j3Nyw=dUUF?Y1g(owWJ>^L*OC9&Oi#?cOIjsT+@_!uVj5*0|82f zHm|IYT)EKfb)N~}%X#Hbe78!r?y%*AYzV;TvD=gF*b4cU<4M%)b!1qL!acOn+t0an zsE$mMsoxpuM;wvsUsOST6gp(OG^XCzv{BsI%^YkdMaRsghZ|cU;kg~SCq5~wTv{%t zGYg3y%qzUh7Sdz{^dOzUj2!;}g=1Qjxlvg)97HiQj8)Ox_)Ef=F(z;!_yk zXKah}1Cl}9a=h`74^zh#LtfM_?4^p$?d6SKkDeGaM%zfnP6vMHui;*u3N2Dv8GCnE z8_5@{IjbmI$5Oe9C6&@g8EBBQ>?ec9cJskC=o)O-aZ1uGVn`*GRVG{zt=~EPzZ%5U zH2oV{((LsSsKae_Yd-6kqq%6_H5tb2VRjszr>gYeXV7%`E#cEjS$WdHT|Ur^Fr|iY zROIg9_4gyzx}izMo~|b{RcNkc`Ieg;&bOvTrrfp1+HG%IMDrzkbzl`q$zPZP7!!he zWN>lKUyoK2dChN2V-BE_OS&0$z*1BnC{dCJ9-v_7y??^Wzc0|(R`9E|sxE&i3ND$OLp)Iv-KK+%+#oM$|taNWE5)xVD8Pg}X~0;u~yl0%$_Ve$cKDFCR;z!G3J)KIf z&t8X99h^4TGXW4EJ8u~~cKd!cHOG}O^FCt?@tEU|CfatMNe8asjtKXuw0W*?G*;Az z^9VqJNcpB941vHI`LpTzS4(TBT9f2u6`*bIrH=`WV;I0ZpYjcQ7dR_sbm+cUt&TtK zTB{|zmXZN1Q-*b%2J@p_Nw)ZTANW73Uv}cjqwNtu{+Ro|`7?8Xz93TOYFmN;L#%l_+Ra$N~ zK3_JiPOKcZKQeV64^OCSQQ5V^$1mDj&9-QZw19sC9Q>>?xaT|qJ?b&x7HeNN-dCOr zTb59WOKxR2WzI2>f0cb@uJ}^^JFD$SPqns*?=7QNGQ_d8V>x^l18WhEm?w}=IIIgl z3rz~e3=*_7E(5zttkla6u@T$uFNW#~dmYoMezW z#{lG$z~th+s$UI>qO^o*_Y+TS!DP6ORU$?W)Z?7}20B#o=vHzY<1`Hu-(JST7mSr> zUqW-7dh_47sP+{aIMr@j#PiF00)$BW?ywZnWFIH&Bc1kle>9Nn=c9qaz&k7&#mt zQJUD3Nrne=aklztwz!fj88$07KQSPD$-v0@NgQxF_3`0*d54!2259GHWRR)CfPQSZ zuV6m4)gKC3O&sZNB~K|!W-pmY{_iKD9DY8v*G`m@S3LUI`f)tNPtoI+0A-Th)>{^3 zGHnG)^T9n2YGcmMa-2 zuYNE(*HZ?GJn(;Ku*A~*tFz^1BflKyzaI6{qIpurK|Rhg!$oMCD_!a4&ZE!h#fEzQ zE2DGb`S;GagNdA1+3lqyDG=?$BEP9*| zV1Jc#x@U*4#hL+ZWf068&A9nhm-xpY!~xDY&jY=6LNG_4iLVx)y{S)3iRY4d!v`yt zJb=Y{>OJs!`d6Y^*@Rh$-6MHQOO`+DJCpkV0FhAHT12fF`!SVanoPvXLbPrUKIsKn zSne6fa6W=R8Msq5d7_*H9rSuHMOf;~E5Z6{`fP?|8U zBu)n&pd15(k<%5?LX$!^L`L=!Fe7nY+3VE$^#1?~1Z0{qPEXPFlfsW~SZ z=KzooCnMBWgT$>f?NwqS+!XWx_x*pBGB{!d%xa4z!)<&Kg=Nlj`C|jUSn`pTq&B~5 zo=H|Tj#2;%-){$yIrpyoI*`SpnVs^~HY>@ZI(~rzlfko7d4$m%mq&u8~#mN{7I&+?L z?^g+Eql(d@3|1ytBvm+Lp1C{*8OI)-I@V%!pzKvxp^I!$2O=OFc1Zb2`MKx0;D3b| z5ipJ-9cP2g5)xNCWY0fd-1>@_%eXCthExJ0oex^KZv^RZ z_mE1^Pvl4-o9!N2fCg9$oM&mqI-G&e0;cmKXKROJG>}^lo+cq=k&bx;azNue53MJ7 zT#GB*ry~7~MdxkWkBQ|%Olk&xVsp@BawFZMEammH4 zh|CU*zFQFj!f`BwEQ^kCxfnS-=h%9h){Yx?jac5o^U1Ylk8>pCcR9cZBf6d{9ITPZ zrZ2R*I>&DWxgs&i!gR;XN#nURki>2p#p9A=8^p>}U}cU#-*r8?&u&TMy-k~Eomr&G zQXvb@6t2iYXPQSKs)O&w4tw*!#W>3tStFK5%Q;{Xijt?ARh{Cd* z?|gz7U=S2@oPIMb4(wU+v885>${Yd5%b#!S?^da^Hzjfiq754?a($j@(=9y6StA{H zH*t?a$>-G7so{}r?WVX;85d}sRE3d;Tzd8BJ*n3g*8&Mf`O*pD{qjcTRQucIH(O!G@0Z+Uk6ix0icK*n@`c>Zw&lcAT`C2VSrDmJ8S2E5!6Xm=09{+Q zW4+iNsUcrF1PvTvPd_O+$pGU%qNj>DB@)PswHpfVSZyi?01vKt@5iM@dQ~KV&*vs# zkz$J7zE(`4Klgihoth`TslY<6_}VYmS!EQ1A@oMMJqBEm!@*wzx{fO;SItV zq?S|V!^Y_e*tsVI)0~>I0>=zjp=JV9jz1w&1f1t2=bUgyAD?QtrE@1F`i!@<@)mu9 zd6GF5rr&m0C}P;aVsJYB-kf_?&B}^ljnum~?S$?-aqCbk`LM$wiQ|pa=b79pOh*M& zc45@#vkIt^1(cH>$u@rF&JQEhb5i#+l%35m?0Z+kG5L+OzcQ{!!w!1jj2?0I29QPE(0P?p zY^7mvM)=7YA-WuO{Atf5N+eawG68{(GERRV!l*UGut_W*WCkm?-tR0!%*O|Y!E9q3 zWN>}zQxt5-(eG|oayxFwAIq9oeU6@83fDIA$`#;DjbAj7GFIq_AD<;_rTS<~o#d?x%1Jp0w&s-jH z&w83Qnp@drL)?0vm!JF|F9fO#wBOLGJhY{^eN5OdBCP;xjwm(rT}^H`GVr4^$a$R3}U zJqcus!%K4WNA`2$+w9e%%B zjs;W(Z=N=|R?Is~XPngQD2{0^j6y}Yg+z#A47pSC;B*WRamnvf+fHr(x&aDEPnONW z9OD@FAm`~^j(+kxESv@%LhbJ(o^PFEDu1Y|@mxl-$hR>_(S~0x;egbg^%8X>^nzQonU}JZVHvuq0lDOvw2dCpql4BOxR7>U0 zDOmia1vhr%sUst&tt7I>kncy`HV4Wx!)KrW096xy=?sL;BN*9Z^HOIl1MS?nILEOB z9<_c;o0fTIni;~rJlp9AWoA7_a!yBo>rg-=o94GxD;&J3UBr6+WYgBzM>8>r=62;% z?IJOdIW5@mF^;6*3dc~~n%+g73lv0-I9TDnQs?|?iGd|$NRO8voBP$2Zz>4nFHZP5 z?Z~0Nc|LhwIMvAVP;%KH%Q*U0PxgZ>v)eN5aXWcs7?efN0CmV7zgnotB4nk|-+OC0 zNm!toD8i!Rc|?u4aLfqC6^|i$fJR9pH4J`q`hwaQeX*0|+{OVJ&niE!*Vdh6vOXg& z5?0GPG~;UZJzF2=6(mwD7jK0EWl}_pr*_^mf<1UYgymopdQhdXK|7j}TD*466{r#~*@~m`3~W35inDKLZ*K$K z&XOr;KoY&#V5dBjp51>+%NGq5$|O#Rk=tS-@tp2s&Q5cTZQ`^hneE_l=B)0?_ajya z&DdkqRcOw{n<=y*Zeo+pZI-e#jgprR zsF|P>MK6}+B#a3dF)F9MTl+jM^Nb?E8)y?f|j8{DJdLA)JOH-Py(=6O1M#XLIrE?<6jUuc&e|Oa3iOxp@ zr?0hFX|5uWOB_%DVqqpwmXLjW9Pyt)?^B?O66$!>)I%FAN@gu1D;|KJNXJrry{f#j zymrLLnHUmZC+>`76Q13;tm-z~A}O;$O9n`C-@K5!M!*3WU@)MLNbk;hC$&%INgQ$p zX=6zke)1+CGY)a|JwG2>qjK`cYPTj0)6Bb)G$olvKMudrpn`cmQu4^c;0(a$AW4qC zxf%UyBR;SnGv=xm4Jx6NzhkBE@0AwLp;eA*s#JrN~DXP7@jgR zbJ%f;vuyKE@?6aBrQKzb%~<}#rBY`zahDG z8D89eSrBHZrt3QeR!ux zB4}e{D~q?q#H|c0&?tflw(p2G6yR~e z?g1m8Q(2&mzG^U+B;kfihaE;p>N-`4o$h2&B!%~!$j(V6&svkB3RgtwD##vPkpBRq z=LBtySvVa4ARK4briGzcC7c}IO&p4Wlm+s@&Nm!j@IJq#QAUfyz%+%pEB4oEOHXPGmd)q6(q94 zqwOA3!wSgKssKWUJaSJY4?~=NO;aVLmOm&(^FY66jo9y!P5}cQ2*Ds6bU%&K&`TTn z^SP1$-h5^dxRF8NV}cJH{e3A(rgBf2k;NQRM>WKcu_nisxaW6%gQXYuIZ{=cKQ)&i z1H*cKIR14;NbglG-AtDD@&Lv^I1=1^!>0g}e*;g5JnaGzB#9&L5h%vuI&thX*Vdt{ ziYb>-V={!fXw(=Z*llCl20-H&&PPH|aCtpyGivj!td|KZM{>&6+nBIEr;Kyz5B~sN zVs9!{B=1nI%dQJ9Ps`t$edMn3EGs6+Wh~nkR#iQT80f>XtEQhZ(+H-9EOxQN>SCYm zFl|^Zq65p09-Q;?k;VYda(ZB9%zk72rV#HHwakh|yU1|Ppx}|yJe+-MnU-ro9CF1P zDIrXon=-E_@I3bP^)+ecx|hfh!ohAOR%eZXj1j;rI-gAQ)cV%#G=(}7T8z7uAX0PW zMQ;kN#6^b526MRo0Ck5>G4D#ueA6&yNavXrL}ktwuO0sY5n7g|ZJCl~kM~y!;jR%` zc7xD@2q2!s8n39&6WUC^d@Xyqe#83nDI*F;J;zGtzch|sT}H;{;z^=e zV}eU`1{IN5`G-GrW4<}(0|TycMahHZa~X2(rd4D2PxPhoVt}-)(n!pw$~(4_-HzUS zag6cn#Wq-_VCdUWeVqB2ISg~0^zG|c?A40B$;?T;ytXo}&B#=PW>^z}$JVOLIR<#Z z+VV@wt8?-W4`IpgP`vEB?bLajN~$uGyKu)!xTzd+NDPYdE3cN%fJi-ZO><5+>O`XC zIJEPUm+L%NCfYT%S@6IwCnMN{k@Xd3?PrN2yFnA%!n;a&+g!2f@?(+Lp4?SCyREk> zk%(k?qG5F;Qw9-{=tl%~=lp27xSW{>mm9`#A_`fXZaR_BWak*qN>t%HiWL3jp$u>| zkWFzTK<^wZuNHSYu_WYs93Drf(ySXZ1f%T{T$W46>*$`a0nx~_VlY3kT8xr zQo&_wR+8iu3xm%9=bkao9+>V+X&jdm58WaaX)ai*kNPB zbe94-2Gh1dyY8Rojz5)Kn&d+ed7|N@WqCH{Jme60&Irile_Dw7Z~$U+nWI%DT_gtw zC!jdV7~`MnG=_V5fkiSrhiWcl+6llo#9&}0SB?Cb(k-m4+;ZJd9S38R+|@{;junY*k$kw>gSP$KSa-*#Za=LH zytII;G_1SWgO$%X{CZZG(Ai4y+>y$s?qr0C%PK3fV1fSt*W>i7H*8W_WdNB9?v`nr za55gJfuDM1yTv4YukVi4m^m$m2Rvt|;Z_{M98x=w(3EY>yCfgxD;Y{m!cx@ATbSi= z4l?XFJ_(Hf03*lKwN8&X`QuB5Tb5;Q%r?e3=dVNU&pjz^?kpshD4JVP@4&L$Jngv7 zarhtSS1&*z(Jh6%Ac7``AhR&XCppgmR#Vaj)U6^Yqm|q&Og6^|X5QgdlxKHd;~hKH zZ*eWjJ4}Ys+TDe@nJZVDzU*Av4U;tYS$Q%X2aYAwdnsLBTjYj&YHmw99xB$~g=`&ArP>=EzQ2k063F_ zVbzsL#=toRNGCjJJvb)0-F!lp@=YR{KXw)!xhxwzj9}ytImfkWJ;ZN`3>&3VHY6m; zjy|5}tzv3%Tz_TiK4|lv824GQa4r%Y)Vg?qN zFt#5l3!dQe4o7j?yv5?SwSwGBs4Um=UP$ZPd7Z|f#=yHQ5Q|&C^p_agybZ)QGRgq!$od-S#>Gl!>3J*V z!A8X?4Z>RmmPKctc2r^O@)45TxX&b!^~XJG ztkJfhQuQQuTWKU{qjcJK_Q>}gjY;;1?(OA#jg2WYMr0%^j=1K$w0%7}wPFO1R9`I_ z-Y>RHl3c>BRixvFJY$e@525n=1eT|G+~sWY-DxXbH+zJ!<0Pr7%(?QxM^Zi-(nNM*e)xQl5h zG0gAajxi4stqVjPg5HSme1`TIbADvfkzuSmA!bamxYs zxjl2(3YzNL+IuLj9a?!yBRn@T0-{iGyM1tQa(n$NIaTF1gzW9m>7tuW)k|8*4a{&` zM!OD~cjPlLIU~#?JspYw)Sgo9}>B+3bp7Pe#;>}hY>sKYr3ns|X!NRj=jIQD{ z?tO7noj}hB0!dgSGe;ndxD0X!PH~^eeJbp;Tgz{7v05xaRal7|gd4z&I6Uq=s#(#-(o;k&H?CM#{m%6&Q%Us*Wb0E(` z#NcH1=hroLZLVaG_tvj!kj%>*Y6jyTcp!|75y!yJXu4)`r#LoTjv4K)McnrDymO||Bn%a@I**|s{uIZ%Sm(O){HUJg2(|`b#g#*L z>`y#>D^BL#_A7IL3~30RhUT4!T>k*D3CjQvBy`BnYUap-NhB8y1e0uLgh&}=RvhO& z06F^cQ7N?}wv{zBJ4>DC^BvmRSe?*W%NUW-LBK4e5w);*JoVzU?=-8~Bxw`u#RQx7 zOK`9*)7NP|@z4&Z>zdnzmg%k{OF4A*NEglfOo&)81Lq}93bEt?&KM50fqQ!;#J84? z>hZ&B!^=l1+i`$+BL^dop{?P2omg&VS@tZAuXwR4G_$NryUXWj{&g&|#VxG6E(F0g zskB)N$r~{w5~O6Q!wio7Pa`>+Uzo*XxQ26ce5)P1#^yFEMmi32f!q4k@3cp2acduw z6D7)+rd*iIU=ff;IUQ>$#`i~C(qjem7HDOP2a4L}Hs2|5NnydqOcB=y)Oyt$&1TN- z-K5j!mhnR>sr$_%4ip3&1}8g@(>(4#0U2C$K7@K2#lDWx zTfu7u)%?*EXO-_Qgg#uE`=Df!pmURhlZ;>kT|TvJ@HL}bT*j8~DBB!yoy#I}PIw&p z0h-FZcex0^?%J4xY;^~*3U~C&nA4d;w^t^1 zoXtJNmvc0dG>l6zEZp*Qfu1@F$~V@s!xiP!3eN*GLL}$p?m5q=LtCkRATt)U{ok6o zxx9s32+yE7+H=lNt}2D>)~yMT%QKQ&bHtfd1oy=|v)4^>Ta=C)l)XW5Wo#6Jv9a@j zZG`q6arFMR5B6kGq_fL6?opS?S(GUesr1Rf#S+^svR+4Z0$bZ$z>&su=8?*wAd{B) zk@}C9u+DHzbXL-Nmr&i=&24clt%z%QWr1B*MI&zb*bu`51Rf85^hLg71vLp?DciY1 z*(QWdEvJ)Z2`wD=i8{w793PY^Ib|aui0BVJYPzJc&v_gkRItq$W;n|39GnyRejfE! z<57^b_7X=N7SDe-pAF@iECKm}QgA@Y;He{mD&kE7LnB1)VS+I&~{DCrBOI%3Ioijs2d_eFPi&;O94XJ2SGig_#J1AGYypZX+w4N%?Py~pu~F9w zNhcivJXR&(5wO0A&DxEj+=6ztc@?8|X+52wc;u0;E|<)lO%Yr%Zi+^8!3QTD$8K@j zE6Yh{wY$2tmdfc2mPsAH$s&EjCPS0B5O5S=f(hhTElPaxdK=NDE86;*4>in}pKFFV zBMmz)U4kr%K4M93gmeH^yL%?Oh1%tcG^Lqb5O$yLujN#(Ee+qDKACB8eSK?t3tHL0 zH0DfM){{WtpCn+06N^1AHhpXKA zM&{1-Oqk2XBq&5+udiYEx^dqf>z!$U(h=g2G;MRbXqB?L9W(Sf71ZlCrL=o%n64vJ zB(g~~GRSrA!U|E`j_vUT z(!pUAS2N7fi^q>D>$`WpP6F^c;Cs~@`R@FiUDj6t1Y$Uyqxod#wnB zrb!Ww3E_0Nm*!pLz7Jk`(#XeW#loDPHVtm>$%iYu4o zWjt2$+izggjj~7~g5%3)kz1JebW%EV!2Bzoz4X}!a9aI`^rHbJ!>yhzSFI) zZA>?|h@MmVwuy2?ix|hwc=>tA7(Kq3=wY0BHxOQ~ogSi=?BCj#cE)9mbI`|;xkhR=JYm zOH0eKxL%ub9L5PGa(T$sX~NGCpIWpKcJz^?;5 z^NOoESfv`U)1jLz5L-=cYYJORwy-wHCvC9j8CT;Rp~+F4XQ(xetT~xp-DVdE(j&^i z^ge^ypM4}v42^p6S_5qxMRva|X&ydeLHoN&Mr2wK|S8^~G}GfifoG|ZzM zU;s%SNvA4R8MGpv?C0%n=eUkb-?O}Wev<=Ws$w)`ZSWnfy_x zK9_1dwuaYFmE)R7$N->xe1wg|za8>%UsC)&{hGWNq{tiWR@WCvx$UK${KjPm7~m0} z4_fq=7LFp9HU9uZ^Q^~@@HlyX?KvNeT5rNn7;EV)NuX*_NpPYoK{y{~k%-6&pzbAl zoa2wqzKZbY?0e&B;L;7{v@yct%5)%xSjo>E@I8UA+3h>QS}=lThflGFNZowPh$8@; zj5iRY<$mOnq45OfC%-&eW=^Yr_YYsVQV8tkGikPQ}4}v5#gWNpTIsEwuv@4#4rVh=AV9m&k&UN5ypN@H z!ksv+&y~jK82o(iIlq%~YRNFUGWBbhK1SpdY`8k0v4& zcl~(JB?gCOYYB3U>oaZhS1j(XJa>2D0dV@-(_w(m1{ z-p3zKhPper7D$T84A7{Ra*?oBbv}m&ueWMg9Ie7e4nP6pgh*9zbNs#iDY~l6>V_Rt z*%U>of@xLJ3p5`tS8!qZaY&Zo=0h?>A=uwEWRQMepywwQ&|MNOW|C$3R5m3&19utr z$j{Vz)^rvPGO;qLgnz4aem7&M;CMC3G~AA=NlSNQ4Xs=;7AO`&DPpn3w{qZ)M}9iz z`qgWT82t2EAZ82#ym?)!!z2=UglQ{ft82K=Z;7J0IH8_+085s zCq1?^)vjQ**l^M_50!GDH?=+(AdPM<R*|lk<&$<8wt45Sf6i+r?rj`26WFfH46PbPZYy8igp{%W9QE;T~gt01e6+k`t$LCW9&y#HVK1e&ao;HquIwe<`E>r@D?YRJ4C|;a@ z_5T2+R43*s;gTW{=}ONl+(i!M%L!BWdro;LlgAwatT>=}CEYEy`(~7w-M}l7e-psR zYTb)Wj(OoSTVKx#d{mpS_JQ6;&KIHQ>nq&E^bk>+gzG53z{ znIn)po-3l%EYF;mWjvHP{nTxh1JjzVb7ZgVY!IU6wzxw^pW9|!qGOzIohOhR5u)qjw_*#IAQYG?qTE~JNIL+u6?-Y z>r&5b&WiBjMJzU}9Iv^o)KX_uaPBra!X7DMW%Atws#-$3lw+>oMn1WzBC--qCB?<8 zl1#Fg;PU=e;PJ<%4?*i&a$76Ljy8!4t}rq{6=AI!M^t|{WneePjzcbeF@g;o=`$w_ z%;y#4ww~oAQ5<45&eZ`@FnfA?kxZ5~jyX*5PX_m9k~BM6qXb}vN8mMpE*yOC6~FgRk}#!u3%Mo8IVsV2Id%UlR`gQG4+glZ8 zmO!$nma(eEVp)R%21(=(uN}!arzNS|3_cy}V~)C>aAlr28byhL^5a5F9)tC%Yzep* zO+52WehSHQE^@>cJa9&H*P7~}hTbt8Es+qp%PT2u!zaE^d|)5xQlu8~`TR31vMVtN zM&{@V1CxMp_||USjjGb5m%9U-mL-}5wrLi54bn5nv9hR-Ip;mbK>GCH)kla;bm;K? zo;5{|IY|Iu6N~|$T;{ra;RFve0T-Eb413Zv`>TP2?0C+4o=-z%ru#L^yo{(p#EOhJC?H@k z9N^<19CX3$=C*000ne2&ka^62D&!0TeQ+=;YYP}4Gu$v)i$cL&2~x5)FvMW>85|$} zy}HJ=F*b`ho2YHT^DaS&pUh^ucli}Y00bU#4oM{b1028^BaSa5tfdF;jBZF}?teV- zTk}TN_r;y#lmfd$fYImZatQu>RU>S&-x;QoA0R?j;wx)_lPNra6n)TedF_srqctOw z*{Q#IXi|>mXO>9fg~iiH8?>$)3b`W~>CSoMJvriuEM_ntG^7mD%_I!6mN+@!`gG~& z1#S5)ZxZ>gg_s77*Qj3E6`6REn9Mh#>4O895zG=HEAp^xau^Un`t;(TEMG&v375j9 zz0(re=Djd9#yRJ+w#<>n0+wYShXdxve&g1!n@{Z*SCy~y<#dnt5ZkLrTdvZ*l=LKW z0VH&%=~mD|B=&0P&`0HMbsxNG7<0M0wg6r`bL(9ln?W7Nl&!cbvjW*XkblOrQi^0_ zGRiTNeJS-0*Ra^O~CH!}gO!_IC4RGOzkXa5tAB$6Pm6KI5fs z&l*|V8<``G;hs=pWgD0`pc(b46(p8_Id>T{B$3?iJ6xZ}wN)LDmamrC=^YM6^F$Z% zMv>YW-aA;;R^mX?N6*Xw;9#7dmCE1vN6oo5*0Jo7_ilDOiO)TG>Hd0Gu*Gc)-6WGv z(g70*3prA!Cjfg8e_AfBAWMXjHF;(L`C)Jrx99czsBw!t`dDX5Z$swIQ^Qv}ENt)g zb&W0$%J%@5JoC4x)>Np^kDn;~aif z%4x5*NELTT(*UwWIXiN3#dS9=u}q^43?Wz{a-=qJazX4l0Qy$k*GIu)u=bY3(ZwhF zQ7Rb0YRsQFUonP$QIm|+7jZi+i`&FfR&CdDz6cA0fWG|>dUdN2OAMY{4jNEV3pRbv z^37y009A$0ydOFacG!&04@%38y4W0D{+;zkNFlG*8xq3>INXPOD3OPi&gQWa~7 z5!7YL=teV0}=zaeH z#*#Z+?sS9qQR8+Lw2Dc<;0)u`_Tsjqv@(Mk2pTWD<*_W^U$0I*D`M6ae=6ev0f;KR zY7}5`&O84ApL(m63f6u{3w>kf%NRafO%p2zc-fhh61xUC2av}-m(+?Z^m!$c^vqW( z!#5j77ChiL9^`ZHU9HZZf!&dW(p`|VJAg{JCwJG5qaATgi%pU9M^SsXA8WaXNm|Q!NhSU7C&E8z!>JSuHu&vAd#QTVyfhwqCRoQZ~na+*h)5z z=PtIp?Sd+Zm_8B0jJG}i0F_otIb>tL%ta>E-zun3#Ao_{O6e`FZV@+JIx-nsW2)^3 z&|{uOT)MWnGei_#s<>7b>9iRM0|exE=NRm2ZqdzEE1XpJ8Ihz+i*!xbcu)r4VtNpJ z)NyH!ttyzNh&)A?a2eq7k;wUn=yTS)fn=mItEux8u~2eLXQd>th5g%F&vd2Ra$4~t zF~B_gU~}7=PVEYsMz?_p zsz{t0iNH_Zvi{^S8&{`JxBzuM`_xj~<~&BMVLP{EU~@{$zF3@;b`5YOc+nzKGZ-1# z2c~-;YH5OXK(eDOY&RS(MtWCI6^OU=ZaKrV z`5kN0-U2R-!m(f7?Up~hPbar*p5xxCU0b8f(vVs<46KUS=g@oAb2iN>Q=pRfPbJkp z9C&+KxVO8SD@&>E#$H800)xo}5C_x_IPX~6Z^PR?HhammbTRp|Y?jxZttasD&OpvG zJ!{#MONI!XDE;$9tkJJedcXENGihx%lHk5P(hkyCb_YE1ilr!}?%dVUheXdDy70c2 zG>DtqK|2+n^Wt$N(LeY=Ht zw=}cJyVRfnDeIH!KgZIjTWQhA?-E6_I3@~-7$<1$_-3g~&6&##t+C`czXOCu}HC4NrDOINIj~CH?7HE2Bkpo&oEvdL= zjJ3ERFytuXsOnGn)}E*ElSkEIxVO2pTYS2-dr1M49FjVI7&+@+<0YcP=Fr?*!o(js z=2B#hWIS&rd0;y6PrCa(xrQry=&xnAAH2G>EEKB_2G#(KaykB)JoOsBh@|CF>W`d9 z!G8|gM+9aV=U7;kjN6P1`tVLGe@*a>mY-_2i5o;*Vy{gXN7F%xpNb=l9ep`OMKnUb+Xyb@|ZR&#{U2^NZVC`@1Fb| zj8s!wxs@1h4Ikb?At=YxjsdKcrDA=YZgbHDo;8zanDIoVLk3a?co^(KIl=z5avif= zN+VQO<~acQa!*`;jZZbK!cD3|JcwD!rUH*@v7aIV8J=MCDDtjG*x5+uEDs#6MhA24 zT>RD=r54Oso{7-tRWIO*25Q)58=hCs>#XBpsogP-%oe7WKef|D)EPL{rLNdD0tU0GxsuoMoUsmaMWq&g^6rn%ZyaHxZ0A0$ zxPD(XbH@uQYh${GBBgcjD|($A9yEn6uCMQnrK_JYrHU5Z4tpzlcggHM#dWsY@lUi( zdS!wcqghpa!U)L9G2@(rk@felpC$0_qp~!#w=qJjF>E0*$bo*iP_3L}85lp0tZ4od z)%6V%$koyQ(3^bVCMR}z;P80kkzDwkH0iEnwK^-)gkg5k=oY&5`^^N4zI$0BZzIl> z7KK5<00H+)Ww3b!_XJl`F0SpSia2HpBW0Qi9R!3va&ibEl=Q|buZFx8sS8rK0g;d^ zD#oN8jnl8LD{4J1?jvy>+;8UjC1bgf3r86DBe=*o@A=ci!f}qM@oG*S-3P9zZ@JFA zme(-LGB=e!BhC$&+=JXU3j5-(-pg#qHkVN0oTR0`Zydqp0(%qN$1b!nNOCe z7(A#W1Sr5Hb~qhBtz(Jrt@R21&22Q$7}VYb3_`|xlY@cJQ|nHnllM-lFuk=qnd7*Y z@Y^(^TW=+qm?2ee4h}mS@?RE3b#>+3$!~I-=4j#bpb@JTIAW~1&lo)mELYOG zRh<$!pb8>+517D{fWC*{istp*I_BM^7VIwXZmq|XBizdqdJ)Gt&T-crdK$rD+`5|7 zjBR_>_qIq_!XFNNK zIGg2XQ}%s1+Dn5nO>Z2(yp9(vRN#-B+a!BeX=!K;#CEN36heD=^X_peCMyt5U>(UD$!F$*=;Hm*s?40{eRJ-DnT2tq}=uIFbC zon*5sn3!5y#7*Rb=V62)@CE?{D=y0FT|#ubN#eMISDD?eXWCi5W^bIF=g@kL z4!EjTa?t6d)wepEYrAQLKWZ>OW071j0D?MkjtC>Ia~h4s{qtT2GfG z3(JEso=wdx=m=FG!;E7euQf(3cl$16YdDr>^A~(EAZ0Rk`A-Z!yn59cd`Bh3^Tj^M z?VPejI})LN{-e{^ABi4VGoD=5He=PTtlm|iE^f}p~$Y>v3?_?m(nxb7YZR_S0_ zzImsd?T!`c{2-hRXN;as0jz0W8>Y8dC5GxWW>%Ra+E}-9)SPtx0QJ zixiKNs58kp1mF&E2jN|+qLNx1?sj_{x)sq##IdE+LQAs6Bm^@lImrjqV*vjE^{PEe z;=|2rhPRI8K>g%16Xr&_AG|mK4tft!gIvR3+{YsQlIBVAmb!*m)l@Og0v@M0&QEei zJJp1M-A^!?<&%7>vJ@Z?qhTyQ?a@-q%xcvwKB@zD;DP-y!+Qn{iC(7 zXGU4zx(co{xrCYLp6B2EYss$k8><#E+Rb-yZsosyI8|e}?z08sJm-#?uHVBJ_omia z9^q~wg^9Y|jlr?k>F@7WmVr^nmvcHx>xi!I*v|38I>@k?+iS%P&rSh|gNF;w=Skr;blPXy)_dXY!;!EMVu5axmP2M?4;w%~#U?&SklU ze%Wa>GAi214Yo!z%Vz`+Z~nD%N_LY>#uXZ8VW#+>S+w)*UJE;^qjqS;!C?qI@;Sj_ z!2tC*`d2J9+wZsD&2b8}GqZ0;fm;W&0&>bh{^|BP>0X5tYjnzGf?MtBncY56^J4;6 z+l;UoBlY7s#n${eahAA*qKNRp9UF9mzBtFdRJo;VG0yECo8a9>#(g|ImuSry*(0UF z5uEPookUa{0sa;QayuIJF9hG;HR3}gD6rhzGf3}n%e8xOLC+aE&!u$Hykllz zc_}SRGU>8u%3d@k;^r;3w$`q)NbFAoZgLxU9lu)Uq<~2_AQDX^;Czlt$>tt#Gn3bV zKLK8!uUlE&MI_MK!4npdAeljCjdDQ%=O7b~51_9o)$N6(FeE|k)@cWsA!6Hk#(SJ~ zIje5Qy!U4{XQ{1*wQ+TMGsk0h5s(#4%jPKVNdN+HGt>@nabHe&Ze2T3w27I#!6m4Y z4=qWIsRtyUFhRx#f5N_cx6*C(8#{YM1~rT2X;pLIsr)-vuJ~lnr^g&o7G<}$XyTGV zmB;@8So4a`FIG)foHX3@p=A`Q3`E4TDuNw=Dzann$j|hw-Cp{wn*EiCzc@^BBM~%<3>bK9zUSnlPHNuc2wN z+g+o^5x^_3$eWdY3n|Ds&qJEW_@Cj_@;ulsOiI^5qeWl!e=bNJILOaG%C|f|(8uOp z2_|-s50HRYXc@^KzTW=TU&a^lTv|e763!)7S9w&Z+;|{oIl#v!9e$O1I29))h&%=x zSs)Yrrr=KgTC_75%I;E69ZxvHJ-XMT>6+BBM+{QBB08%=6#|{z$s>|Fe!jKK*vD)3 zi@P^$NSIPlS+;}UKAeG?-CaDw7CEC6!baO`)yQH;-i-)2&Il)t*I^~t2 z8C(Ivo(Rdt58=;x?*9O`;e9&R-Bsk4BwsKbDQ+?A*1IXmvn5YcPTbsE$1atquAlyn zWR6JfCNqXme)jY7usOin$IG7iEY%PjNi8fbre&tbmoumdWD>`i}L&*h#3{!*sW5u}Zj!)7IG%Y$1*x^q~>+WsQE%Is3|U)Z?6Ex9d>d%x633dX=Tl_PAF_-7Z&YMu}On z3CJD6&lw*|< z&rh*xyWluFgW?|gm zk<*?%YoJAv89b=`nWjt`6{5ga>_=_~IrRt7*JU?{yoMwg-J*x){t`*{J;id8PbQme zk-(vgG>TqE+`we99P`((_U*-TO~RTK<#xzs)h-c25L3%wba_`_eE7i zYa>XAW|?H*0m%b69^8Hv!b>!lQ0{1UJhNa*z>)ZlI)8_)bcI?AVH8u|6K+e}!EF+- znrwWagMorhGoCVQSjjXfS);p$Qdw5wIIeEtwN~>cxsKd3a5J}SWDt52=y>L=Ea@s- zd2j^t;Z-*eY&RZvE<6*f}(r=)Vm965lwuysbk%^KbGORfPa!5Jk5C^VDpp8D- z=F~KBi6asI@f;Qby*{5>#Gg<5Dwas1iU`v1m%~U=hCUdWRoB2jOe3e(lJu8jz}H3>xyZ# zHxS7xMg+>P-ekp8g&dxw9^C~t?#wwEE#{$NGJsM|yA^!6W@Rmb$t(yXC)1yP^!1<5 zmRSv)kz2@tt%5qNYyQX?EzoBt*Qu;yVJF%PFetbik%s|KBN^;#de%NROyNW?zz3kE z�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

internal class PixelOperations : PixelOperations { - - /// + /// internal override void FromArgb32(Configuration configuration, ReadOnlySpan source, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -36,41 +35,40 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - - /// - internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) - { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); - } + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + } - /// - internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) - { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); - } + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + } - /// - internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) - { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); - } + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + } - /// - internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) - { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); - } + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + } - /// - internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + /// + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); @@ -83,12 +81,12 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// internal override void FromRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); @@ -98,10 +96,10 @@ namespace SixLabors.ImageSharp.PixelFormats Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToArgb32(sp); } } - /// - internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + /// + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); @@ -114,12 +112,12 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// internal override void FromBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); @@ -129,11 +127,11 @@ namespace SixLabors.ImageSharp.PixelFormats Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToArgb32(sp); } } - - /// + + /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -147,11 +145,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromArgb32(sp); } } - - /// + + /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -165,11 +163,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromArgb32(sp); } } - - /// + + /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -183,11 +181,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromArgb32(sp); } } - - /// + + /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -201,11 +199,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromArgb32(sp); } } - - /// + + /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -219,11 +217,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromArgb32(sp); } } - - /// + + /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -237,7 +235,6 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromArgb32(sp); } } - - } - } + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt index 8c4c6b58af..0a58504e15 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt @@ -13,10 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - <# - GenerateAllDefaultConversionMethods("Argb32"); - #> - - } - } + <# GenerateAllDefaultConversionMethods("Argb32"); #> + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs index 9232cf4549..711a9d1c16 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs @@ -23,11 +23,10 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - - /// + /// internal override void FromBgr24(Configuration configuration, ReadOnlySpan source, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -36,42 +35,41 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - - /// - internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) - { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); - } - - /// - internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) - { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); - } - - /// - internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) - { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); - } - - /// - internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) - { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); - } - - - /// + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + } + + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + } + + + /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -85,11 +83,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgr24(sp); } } - - /// + + /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -103,11 +101,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgr24(sp); } } - - /// + + /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -121,11 +119,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgr24(sp); } } - - /// + + /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -139,11 +137,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgr24(sp); } } - - /// + + /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -157,11 +155,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgr24(sp); } } - - /// + + /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -175,11 +173,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgr24(sp); } } - - /// + + /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -193,11 +191,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgr24(sp); } } - - /// + + /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -211,7 +209,6 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgr24(sp); } } - - } - } + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt index 56e3bf9ba4..84b89aa32c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt @@ -13,10 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - <# - GenerateAllDefaultConversionMethods("Bgr24"); - #> - - } - } + <# GenerateAllDefaultConversionMethods("Bgr24"); #> + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs index 4f56b75c5a..b669dd5348 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs @@ -23,11 +23,10 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - - /// + /// internal override void FromBgra32(Configuration configuration, ReadOnlySpan source, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -36,41 +35,40 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - - /// - internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) - { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); - } + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + } - /// - internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) - { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); - } + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + } - /// - internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) - { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); - } + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + } - /// - internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) - { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); - } + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + } - /// - internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + /// + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); @@ -83,12 +81,12 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// internal override void FromRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); @@ -98,10 +96,10 @@ namespace SixLabors.ImageSharp.PixelFormats Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToBgra32(sp); } } - /// - internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + /// + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); @@ -114,12 +112,12 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// internal override void FromArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); @@ -129,11 +127,11 @@ namespace SixLabors.ImageSharp.PixelFormats Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToBgra32(sp); } } - - /// + + /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -147,11 +145,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgra32(sp); } } - - /// + + /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -165,11 +163,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgra32(sp); } } - - /// + + /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -183,11 +181,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgra32(sp); } } - - /// + + /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -201,11 +199,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgra32(sp); } } - - /// + + /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -219,11 +217,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgra32(sp); } } - - /// + + /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -237,7 +235,6 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgra32(sp); } } - - } - } + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt index 6563ff9072..004ceff51e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt @@ -13,10 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - <# - GenerateAllDefaultConversionMethods("Bgra32"); - #> - - } - } + <# GenerateAllDefaultConversionMethods("Bgra32"); #> + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs index 81882185d1..288c5d92e4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs @@ -23,11 +23,10 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - - /// + /// internal override void FromGray16(Configuration configuration, ReadOnlySpan source, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -36,17 +35,17 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - - /// + + /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -60,11 +59,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray16(sp); } } - - /// + + /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -78,11 +77,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray16(sp); } } - - /// + + /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -96,11 +95,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray16(sp); } } - - /// + + /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -114,11 +113,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray16(sp); } } - - /// + + /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -132,11 +131,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray16(sp); } } - - /// + + /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -150,11 +149,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray16(sp); } } - - /// + + /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -168,11 +167,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray16(sp); } } - - /// + + /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -186,7 +185,6 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray16(sp); } } - - } - } + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt index 3db96d70a9..3cbc01e88c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt @@ -13,10 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - <# - GenerateAllDefaultConversionMethods("Gray16"); - #> - - } - } + <# GenerateAllDefaultConversionMethods("Gray16"); #> + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs index f6678a4f87..f7e94788e3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs @@ -23,11 +23,10 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - - /// + /// internal override void FromGray8(Configuration configuration, ReadOnlySpan source, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -36,17 +35,17 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - - /// + + /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -60,11 +59,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray8(sp); } } - - /// + + /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -78,11 +77,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray8(sp); } } - - /// + + /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -96,11 +95,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray8(sp); } } - - /// + + /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -114,11 +113,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray8(sp); } } - - /// + + /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -132,11 +131,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray8(sp); } } - - /// + + /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -150,11 +149,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray8(sp); } } - - /// + + /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -168,11 +167,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray8(sp); } } - - /// + + /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -186,7 +185,6 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray8(sp); } } - - } - } + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt index a65d8f2634..d35843ccda 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt @@ -13,10 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - <# - GenerateAllDefaultConversionMethods("Gray8"); - #> - - } - } + <# GenerateAllDefaultConversionMethods("Gray8"); #> + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs index aae8b2f637..dbf3102c4a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs @@ -23,11 +23,10 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - - /// + /// internal override void FromRgb24(Configuration configuration, ReadOnlySpan source, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -36,42 +35,41 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - - /// - internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) - { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); - } - - /// - internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) - { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); - } - - /// - internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) - { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); - } - - /// - internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) - { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); - } - - - /// + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + } + + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + } + + + /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -85,11 +83,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb24(sp); } } - - /// + + /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -103,11 +101,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb24(sp); } } - - /// + + /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -121,11 +119,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb24(sp); } } - - /// + + /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -139,11 +137,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb24(sp); } } - - /// + + /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -157,11 +155,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb24(sp); } } - - /// + + /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -175,11 +173,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb24(sp); } } - - /// + + /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -193,11 +191,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb24(sp); } } - - /// + + /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -211,7 +209,6 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb24(sp); } } - - } - } + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt index 796cdeb662..d96c3684b5 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt @@ -13,10 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - <# - GenerateAllDefaultConversionMethods("Rgb24"); - #> - - } - } + <# GenerateAllDefaultConversionMethods("Rgb24"); #> + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs index c828053a4c..30c9972bbf 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs @@ -23,11 +23,10 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - - /// + /// internal override void FromRgb48(Configuration configuration, ReadOnlySpan source, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -36,17 +35,17 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - - /// + + /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -60,11 +59,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb48(sp); } } - - /// + + /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -78,11 +77,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb48(sp); } } - - /// + + /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -96,11 +95,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb48(sp); } } - - /// + + /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -114,11 +113,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb48(sp); } } - - /// + + /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -132,11 +131,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb48(sp); } } - - /// + + /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -150,11 +149,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb48(sp); } } - - /// + + /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -168,11 +167,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb48(sp); } } - - /// + + /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -186,7 +185,6 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb48(sp); } } - - } - } + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt index b8ee99fce1..7bff336386 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt @@ -13,10 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - <# - GenerateAllDefaultConversionMethods("Rgb48"); - #> - - } - } + <# GenerateAllDefaultConversionMethods("Rgb48"); #> + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs index 9c29bd0445..da2ce3770b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs @@ -23,11 +23,10 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal partial class PixelOperations : PixelOperations { - - /// + /// internal override void FromRgba32(Configuration configuration, ReadOnlySpan source, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -36,16 +35,16 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - /// - internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + /// + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); @@ -58,12 +57,12 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// internal override void FromArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); @@ -73,10 +72,10 @@ namespace SixLabors.ImageSharp.PixelFormats Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToRgba32(sp); } } - /// - internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + /// + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); @@ -89,12 +88,12 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// internal override void FromBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); @@ -104,11 +103,11 @@ namespace SixLabors.ImageSharp.PixelFormats Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToRgba32(sp); } } - - /// + + /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -122,11 +121,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba32(sp); } } - - /// + + /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -140,11 +139,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba32(sp); } } - - /// + + /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -158,11 +157,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba32(sp); } } - - /// + + /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -176,11 +175,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba32(sp); } } - - /// + + /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -194,11 +193,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba32(sp); } } - - /// + + /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -212,7 +211,6 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba32(sp); } } - - } - } + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt index 0c4a4c0c0a..6b9e2d1248 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt @@ -13,10 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal partial class PixelOperations : PixelOperations { - <# - GenerateAllDefaultConversionMethods("Rgba32"); - #> - - } - } + <# GenerateAllDefaultConversionMethods("Rgba32"); #> + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs index db9cb84bec..42c40ad5d7 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs @@ -23,11 +23,10 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - - /// + /// internal override void FromRgba64(Configuration configuration, ReadOnlySpan source, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -36,17 +35,17 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - - /// + + /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -60,11 +59,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba64(sp); } } - - /// + + /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -78,11 +77,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba64(sp); } } - - /// + + /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -96,11 +95,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba64(sp); } } - - /// + + /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -114,11 +113,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba64(sp); } } - - /// + + /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -132,11 +131,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba64(sp); } } - - /// + + /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -150,11 +149,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba64(sp); } } - - /// + + /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -168,11 +167,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba64(sp); } } - - /// + + /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -186,7 +185,6 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba64(sp); } } - - } - } + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt index 9409e1573e..d15945f947 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt @@ -13,10 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - <# - GenerateAllDefaultConversionMethods("Rgba64"); - #> - - } - } + <# GenerateAllDefaultConversionMethods("Rgba64"); #> + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude index cc8cb0e2fc..f0675cb5b3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude @@ -15,21 +15,20 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; <#+ - static readonly string[] CommonPixelTypes = { "Argb32", "Bgr24", "Bgra32", "Gray8", "Gray16", "Rgb24", "Rgba32", "Rgb48", "Rgba64" }; + static readonly string[] CommonPixelTypes = { "Argb32", "Bgr24", "Bgra32", "Gray8", "Gray16", "Rgb24", "Rgba32", "Rgb48", "Rgba64" }; - static readonly string[] Optimized32BitTypes = { "Rgba32", "Argb32", "Bgra32" }; - - // Types with Rgba32-combatible to/from Vector4 conversion - static readonly string[] Rgba32CompatibleTypes = { "Argb32", "Bgra32", "Rgb24", "Bgr24" }; + static readonly string[] Optimized32BitTypes = { "Rgba32", "Argb32", "Bgra32" }; - void GenerateDefaultSelfConversionMethods(string pixelType) - { - #> + // Types with Rgba32-combatible to/from Vector4 conversion + static readonly string[] Rgba32CompatibleTypes = { "Argb32", "Bgra32", "Rgb24", "Bgr24" }; - /// + void GenerateDefaultSelfConversionMethods(string pixelType) + { +#> +/// internal override void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -38,23 +37,23 @@ using System.Runtime.InteropServices; /// internal override void To<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<<#=pixelType#>> destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - <#+ +<#+ } - void GenerateDefaultConvertToMethod(string fromPixelType, string toPixelType) + void GenerateDefaultConvertToMethod(string fromPixelType, string toPixelType) { - #> +#> - /// + /// internal override void To<#=toPixelType#>(Configuration configuration, ReadOnlySpan<<#=fromPixelType#>> sourcePixels, Span<<#=toPixelType#>> destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref <#=fromPixelType#> sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -68,16 +67,16 @@ using System.Runtime.InteropServices; dp.From<#=fromPixelType#>(sp); } } - <#+ +<#+ } - void GenerateOptimized32BitConversionMethods(string thisPixelType, string otherPixelType) - { - #> - /// - internal override void To<#=otherPixelType#>(Configuration configuration, ReadOnlySpan<<#=thisPixelType#>> sourcePixels, Span<<#=otherPixelType#>> destPixels) + void GenerateOptimized32BitConversionMethods(string thisPixelType, string otherPixelType) + { +#> + /// + internal override void To<#=otherPixelType#>(Configuration configuration, ReadOnlySpan<<#=thisPixelType#>> sourcePixels, Span<<#=otherPixelType#>> destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref uint sourceRef = ref Unsafe.As<<#=thisPixelType#>,uint>(ref MemoryMarshal.GetReference(sourcePixels)); @@ -90,12 +89,12 @@ using System.Runtime.InteropServices; } } - /// + /// internal override void From<#=otherPixelType#>(Configuration configuration, ReadOnlySpan<<#=otherPixelType#>> sourcePixels, Span<<#=thisPixelType#>> destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - + ref uint sourceRef = ref Unsafe.As<<#=otherPixelType#>,uint>(ref MemoryMarshal.GetReference(sourcePixels)); ref uint destRef = ref Unsafe.As<<#=thisPixelType#>, uint>(ref MemoryMarshal.GetReference(destPixels)); @@ -105,65 +104,64 @@ using System.Runtime.InteropServices; Unsafe.Add(ref destRef, i) = PixelConverter.From<#=otherPixelType#>.To<#=thisPixelType#>(sp); } } - <#+ +<#+ } - void GenerateRgba32CompatibleVector4ConversionMethods(string pixelType) - { - #> - - /// - internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span<<#=pixelType#>> destPixels) - { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); - } - - /// - internal override void ToVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) - { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); - } - - /// - internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span<<#=pixelType#>> destPixels) - { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); - } - - /// - internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) - { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); - } - - <#+ + void GenerateRgba32CompatibleVector4ConversionMethods(string pixelType) + { +#> + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span<<#=pixelType#>> destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span<<#=pixelType#>> destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + } + + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + } + +<#+ } - void GenerateAllDefaultConversionMethods(string pixelType) - { - GenerateDefaultSelfConversionMethods(pixelType); + void GenerateAllDefaultConversionMethods(string pixelType) + { + GenerateDefaultSelfConversionMethods(pixelType); - if (Rgba32CompatibleTypes.Contains(pixelType)) - { - GenerateRgba32CompatibleVector4ConversionMethods(pixelType); + if (Rgba32CompatibleTypes.Contains(pixelType)) + { + GenerateRgba32CompatibleVector4ConversionMethods(pixelType); } - var matching32BitTypes = Optimized32BitTypes.Contains(pixelType) ? - Optimized32BitTypes.Where(p => p != pixelType) : - Enumerable.Empty(); + var matching32BitTypes = Optimized32BitTypes.Contains(pixelType) ? + Optimized32BitTypes.Where(p => p != pixelType) : + Enumerable.Empty(); - foreach (string destPixelType in matching32BitTypes) - { - GenerateOptimized32BitConversionMethods(pixelType, destPixelType); + foreach (string destPixelType in matching32BitTypes) + { + GenerateOptimized32BitConversionMethods(pixelType, destPixelType); } - var otherCommonNon32Types = CommonPixelTypes - .Where(p => p != pixelType) - .Except(matching32BitTypes); + var otherCommonNon32Types = CommonPixelTypes + .Where(p => p != pixelType) + .Except(matching32BitTypes); - foreach (string destPixelType in otherCommonNon32Types) - { - GenerateDefaultConvertToMethod(pixelType, destPixelType); + foreach (string destPixelType in otherCommonNon32Types) + { + GenerateDefaultConvertToMethod(pixelType, destPixelType); } } #> \ No newline at end of file From 4610324f22e3c6db4c1d9cb77b382915d8e17f01 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Mon, 29 Oct 2018 21:26:39 +0100 Subject: [PATCH 257/381] Upgraded Magick.NET to the latest release. --- tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj | 2 +- tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index 0ca3cffa18..bb559b70dd 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -19,7 +19,7 @@ - + diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 04a6802005..86c1a7a259 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -27,7 +27,7 @@ - + From 82646c11b728d2b25cc8e245284a1f28cf51ce55 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 30 Oct 2018 00:22:32 +0100 Subject: [PATCH 258/381] remove yet another duplicate and drop the unused PdfJsOnly list --- .../Formats/Jpg/JpegDecoderTests.Images.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs index 748abdb99a..40de25b30a 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs @@ -44,22 +44,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Progressive.Bad.ExifUndefType, TestImages.Jpeg.Issues.NoEoiProgressive517, TestImages.Jpeg.Issues.BadRstProgressive518, - TestImages.Jpeg.Issues.MissingFF00ProgressiveBedroom159, TestImages.Jpeg.Issues.DhtHasWrongLength624, TestImages.Jpeg.Issues.OrderedInterleavedProgressive723A, TestImages.Jpeg.Issues.OrderedInterleavedProgressive723B, TestImages.Jpeg.Issues.OrderedInterleavedProgressive723C }; - /// - /// Golang decoder is unable to decode these - /// - public static string[] PdfJsOnly = - { - TestImages.Jpeg.Issues.NoEoiProgressive517, TestImages.Jpeg.Issues.BadRstProgressive518, - TestImages.Jpeg.Issues.MissingFF00ProgressiveBedroom159 - }; - private static readonly Dictionary CustomToleranceValues = new Dictionary { From 28b990bd2e2f71f0e24b4ab3053c979b5dcaab92 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 31 Oct 2018 00:25:38 +0100 Subject: [PATCH 259/381] add some benchmark results --- .../Codecs/Jpeg/DecodeJpeg.cs | 6 +- .../Codecs/Jpeg/LoadResizeSave.cs | 49 ++++++++---- .../Codecs/MultiImageBenchmarkBase.cs | 2 +- .../ImageSharp.Benchmarks/Samplers/Resize.cs | 74 ++++++++++++++++--- 4 files changed, 100 insertions(+), 31 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs index 9b968e4db3..8eb1fdda6b 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs @@ -14,13 +14,15 @@ using SDImage = System.Drawing.Image; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { [Config(typeof(Config.ShortClr))] - public class DecodeJpeg : BenchmarkBase + public class DecodeJpeg { private byte[] jpegBytes; private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); - [Params(TestImages.Jpeg.Baseline.Jpeg420Exif, TestImages.Jpeg.Baseline.Calliphora)] + [Params(TestImages.Jpeg.Baseline.Jpeg420Exif + //, TestImages.Jpeg.Baseline.Calliphora + )] public string TestImage { get; set; } [GlobalSetup] diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs index 77ed828ef1..d0d4d569af 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs @@ -15,7 +15,7 @@ using SixLabors.ImageSharp.Formats.Jpeg; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { [Config(typeof(Config.ShortClr))] - public class LoadResizeSave : BenchmarkBase + public class LoadResizeSave { private readonly Configuration configuration = new Configuration(new JpegConfigurationModule()); @@ -32,23 +32,17 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg public string TestImage { get; set; } [Params(false, true)] - public bool EnableParallelExecution { get; set; } + public bool ParallelExec { get; set; } [GlobalSetup] public void Setup() { this.configuration.MaxDegreeOfParallelism = - this.EnableParallelExecution ? Environment.ProcessorCount : 1; + this.ParallelExec ? Environment.ProcessorCount : 1; - if (this.sourceBytes == null) - { - this.sourceBytes = File.ReadAllBytes(this.TestImageFullPath); - } + this.sourceBytes = File.ReadAllBytes(this.TestImageFullPath); - if (this.destBytes == null) - { - this.destBytes = new byte[this.sourceBytes.Length]; - } + this.destBytes = new byte[this.sourceBytes.Length * 2]; } [Benchmark(Baseline = true)] @@ -59,12 +53,12 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg using (var source = SDImage.FromStream(sourceStream)) using (var destination = new Bitmap(source.Width / 4, source.Height / 4)) { - using (var graphics = Graphics.FromImage(destination)) + using (var g = Graphics.FromImage(destination)) { - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.DrawImage(source, 0, 0, 400, 400); + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.PixelOffsetMode = PixelOffsetMode.HighQuality; + g.CompositingQuality = CompositingQuality.HighQuality; + g.DrawImage(source, 0, 0, 400, 400); } destination.Save(destStream, ImageFormat.Jpeg); @@ -82,5 +76,28 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg source.SaveAsJpeg(destStream); } } + + // RESULTS: + // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 + // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores + // Frequency=2742191 Hz, Resolution=364.6719 ns, Timer=TSC + // .NET Core SDK=2.1.403 + // [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // Job-ZPEZGV : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 + // Job-SGOCJT : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // + // Method | Runtime | TestImage | ParallelExec | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // -------------- |-------- |----------------------------- |------------- |----------:|----------:|----------:|-------:|---------:|---------:|----------:| + // SystemDrawing | Clr | Jpg/baseline/jpeg420exif.jpg | False | 64.88 ms | 3.735 ms | 0.2110 ms | 1.00 | 0.00 | 250.0000 | 791.07 KB | + // ImageSharp | Clr | Jpg/baseline/jpeg420exif.jpg | False | 129.53 ms | 23.423 ms | 1.3234 ms | 2.00 | 0.02 | - | 50.09 KB | + // | | | | | | | | | | | + // SystemDrawing | Core | Jpg/baseline/jpeg420exif.jpg | False | 65.87 ms | 10.488 ms | 0.5926 ms | 1.00 | 0.00 | 250.0000 | 789.79 KB | + // ImageSharp | Core | Jpg/baseline/jpeg420exif.jpg | False | 92.00 ms | 7.241 ms | 0.4091 ms | 1.40 | 0.01 | - | 46.36 KB | + // | | | | | | | | | | | + // SystemDrawing | Clr | Jpg/baseline/jpeg420exif.jpg | True | 64.23 ms | 5.998 ms | 0.3389 ms | 1.00 | 0.00 | 250.0000 | 791.07 KB | + // ImageSharp | Clr | Jpg/baseline/jpeg420exif.jpg | True | 82.63 ms | 29.320 ms | 1.6566 ms | 1.29 | 0.02 | - | 57.59 KB | + // | | | | | | | | | | | + // SystemDrawing | Core | Jpg/baseline/jpeg420exif.jpg | True | 64.20 ms | 6.560 ms | 0.3707 ms | 1.00 | 0.00 | 250.0000 | 789.79 KB | + // ImageSharp | Core | Jpg/baseline/jpeg420exif.jpg | True | 68.08 ms | 18.376 ms | 1.0383 ms | 1.06 | 0.01 | - | 50.49 KB | } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs b/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs index f046f3033b..608d3604f9 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs using CoreImage = ImageSharp.Image; - public abstract class MultiImageBenchmarkBase : BenchmarkBase + public abstract class MultiImageBenchmarkBase { protected Dictionary FileNamesToBytes = new Dictionary(); diff --git a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs index f53061d4e1..2be892295e 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs @@ -22,15 +22,17 @@ namespace SixLabors.ImageSharp.Benchmarks private Bitmap sourceBitmap; - public const int SourceSize = 3032; + [Params(3032)] + public int SourceSize { get; set; } - public const int DestSize = 400; + [Params(400)] + public int DestSize { get; set; } [GlobalSetup] public void Setup() { - this.sourceImage = new Image(this.Configuration, SourceSize, SourceSize); - this.sourceBitmap = new Bitmap(SourceSize, SourceSize); + this.sourceImage = new Image(this.Configuration, this.SourceSize, this.SourceSize); + this.sourceBitmap = new Bitmap(this.SourceSize, this.SourceSize); } [GlobalCleanup] @@ -43,14 +45,17 @@ namespace SixLabors.ImageSharp.Benchmarks [Benchmark(Baseline = true)] public int SystemDrawing() { - using (var destination = new Bitmap(DestSize, DestSize)) + using (var destination = new Bitmap(this.DestSize, this.DestSize)) { - using (var graphics = Graphics.FromImage(destination)) + using (var g = Graphics.FromImage(destination)) { - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.DrawImage(this.sourceBitmap, 0, 0, DestSize, DestSize); + g.CompositingMode = CompositingMode.SourceCopy; + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.PixelOffsetMode = PixelOffsetMode.HighQuality; + g.CompositingQuality = CompositingQuality.HighQuality; + g.SmoothingMode = SmoothingMode.HighQuality; + + g.DrawImage(this.sourceBitmap, 0, 0, this.DestSize, this.DestSize); } return destination.Width; @@ -83,15 +88,60 @@ namespace SixLabors.ImageSharp.Benchmarks { protected override void ExecuteResizeOperation(IImageProcessingContext ctx) { - ctx.Resize(DestSize, DestSize, KnownResamplers.Bicubic); + ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic); } + + // RESULTS: + // + // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 + // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores + // Frequency=2742191 Hz, Resolution=364.6719 ns, Timer=TSC + // .NET Core SDK=2.1.403 + // [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // Job-IGUFBA : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 + // Job-DZFERG : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // + // Method | Runtime | SourceSize | DestSize | Mean | Error | StdDev | Scaled | ScaledSD | Allocated | + // ----------------------------------------- |-------- |----------- |--------- |----------:|----------:|----------:|-------:|---------:|----------:| + // SystemDrawing | Clr | 3032 | 400 | 101.13 ms | 18.659 ms | 1.0542 ms | 1.00 | 0.00 | 0 B | + // 'ImageSharp, MaxDegreeOfParallelism = 1' | Clr | 3032 | 400 | 122.05 ms | 19.622 ms | 1.1087 ms | 1.21 | 0.01 | 21856 B | + // 'ImageSharp, MaxDegreeOfParallelism = 4' | Clr | 3032 | 400 | 41.34 ms | 54.841 ms | 3.0986 ms | 0.41 | 0.03 | 28000 B | + // 'ImageSharp, MaxDegreeOfParallelism = 8' | Clr | 3032 | 400 | 31.68 ms | 12.782 ms | 0.7222 ms | 0.31 | 0.01 | 28256 B | + // | | | | | | | | | | + // SystemDrawing | Core | 3032 | 400 | 100.37 ms | 18.479 ms | 1.0441 ms | 1.00 | 0.00 | 0 B | + // 'ImageSharp, MaxDegreeOfParallelism = 1' | Core | 3032 | 400 | 73.03 ms | 10.540 ms | 0.5955 ms | 0.73 | 0.01 | 21368 B | + // 'ImageSharp, MaxDegreeOfParallelism = 4' | Core | 3032 | 400 | 22.59 ms | 4.863 ms | 0.2748 ms | 0.23 | 0.00 | 25220 B | + // 'ImageSharp, MaxDegreeOfParallelism = 8' | Core | 3032 | 400 | 21.10 ms | 23.362 ms | 1.3200 ms | 0.21 | 0.01 | 25539 B | + } public class Resize_BicubicCompand : ResizeBenchmarkBase { protected override void ExecuteResizeOperation(IImageProcessingContext ctx) { - ctx.Resize(DestSize, DestSize, KnownResamplers.Bicubic, true); + ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic, true); } + + // RESULTS: + // + // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 + // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores + // Frequency=2742191 Hz, Resolution=364.6719 ns, Timer=TSC + // .NET Core SDK=2.1.403 + // [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // Job-IGUFBA : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 + // Job-DZFERG : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // + // Method | Runtime | SourceSize | DestSize | Mean | Error | StdDev | Scaled | ScaledSD | Allocated | + // ----------------------------------------- |-------- |----------- |--------- |----------:|----------:|----------:|-------:|---------:|----------:| + // SystemDrawing | Clr | 3032 | 400 | 100.63 ms | 13.864 ms | 0.7833 ms | 1.00 | 0.00 | 0 B | + // 'ImageSharp, MaxDegreeOfParallelism = 1' | Clr | 3032 | 400 | 156.83 ms | 28.631 ms | 1.6177 ms | 1.56 | 0.02 | 21856 B | + // 'ImageSharp, MaxDegreeOfParallelism = 4' | Clr | 3032 | 400 | 53.43 ms | 38.493 ms | 2.1749 ms | 0.53 | 0.02 | 28512 B | + // 'ImageSharp, MaxDegreeOfParallelism = 8' | Clr | 3032 | 400 | 38.47 ms | 11.969 ms | 0.6763 ms | 0.38 | 0.01 | 28000 B | + // | | | | | | | | | | + // SystemDrawing | Core | 3032 | 400 | 99.87 ms | 23.459 ms | 1.3255 ms | 1.00 | 0.00 | 0 B | + // 'ImageSharp, MaxDegreeOfParallelism = 1' | Core | 3032 | 400 | 108.19 ms | 38.562 ms | 2.1788 ms | 1.08 | 0.02 | 21368 B | + // 'ImageSharp, MaxDegreeOfParallelism = 4' | Core | 3032 | 400 | 36.21 ms | 53.802 ms | 3.0399 ms | 0.36 | 0.03 | 25300 B | + // 'ImageSharp, MaxDegreeOfParallelism = 8' | Core | 3032 | 400 | 26.52 ms | 2.173 ms | 0.1228 ms | 0.27 | 0.00 | 25589 B | } } From b798d8dc014a3fbb6b074a11d2137ba00404a754 Mon Sep 17 00:00:00 2001 From: Devedse Date: Wed, 31 Oct 2018 00:41:07 +0100 Subject: [PATCH 260/381] Work in progress preserving isTrans data --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 97 ++++++++------------ src/ImageSharp/Formats/Png/PngEncoderCore.cs | 5 + src/ImageSharp/Formats/Png/PngMetaData.cs | 27 ++++++ src/ImageSharp/MetaData/ImageMetaData.cs | 1 + 4 files changed, 73 insertions(+), 57 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 11c4d831b0..024bd62216 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -124,31 +124,6 @@ namespace SixLabors.ImageSharp.Formats.Png ///
private PngColorType pngColorType; - /// - /// Represents any color in an 8 bit Rgb24 encoded png that should be transparent - /// - private Rgb24 rgb24Trans; - - /// - /// Represents any color in a 16 bit Rgb24 encoded png that should be transparent - /// - private Rgb48 rgb48Trans; - - /// - /// Represents any color in an 8 bit grayscale encoded png that should be transparent - /// - private byte luminanceTrans; - - /// - /// Represents any color in a 16 bit grayscale encoded png that should be transparent - /// - private ushort luminance16Trans; - - /// - /// Whether the image has transparency chunk and markers were decoded - /// - private bool hasTrans; - /// /// The next chunk of data to return /// @@ -213,7 +188,7 @@ namespace SixLabors.ImageSharp.Formats.Png using (var deframeStream = new ZlibInflateStream(this.currentStream, this.ReadNextDataChunk)) { deframeStream.AllocateNewBytes(chunk.Length); - this.ReadScanlines(deframeStream.CompressedStream, image.Frames.RootFrame); + this.ReadScanlines(deframeStream.CompressedStream, image.Frames.RootFrame, pngMetaData); } break; @@ -226,7 +201,7 @@ namespace SixLabors.ImageSharp.Formats.Png byte[] alpha = new byte[chunk.Length]; Buffer.BlockCopy(chunk.Data.Array, 0, alpha, 0, chunk.Length); this.paletteAlpha = alpha; - this.AssignTransparentMarkers(alpha); + this.AssignTransparentMarkers(alpha, pngMetaData); break; case PngChunkType.Text: this.ReadTextChunk(metaData, chunk.Data.Array.AsSpan(0, chunk.Length)); @@ -331,7 +306,9 @@ namespace SixLabors.ImageSharp.Formats.Png /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] private static byte ReadByteLittleEndian(ReadOnlySpan buffer, int offset) - => (byte)(((buffer[offset] & 0xFF) << 16) | (buffer[offset + 1] & 0xFF)); + { + return (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 @@ -496,16 +473,17 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The containing data. /// The pixel data. - private void ReadScanlines(Stream dataStream, ImageFrame image) + /// The png meta data + private void ReadScanlines(Stream dataStream, ImageFrame image, PngMetaData pngMetaData) where TPixel : struct, IPixel { if (this.header.InterlaceMethod == PngInterlaceMode.Adam7) { - this.DecodeInterlacedPixelData(dataStream, image); + this.DecodeInterlacedPixelData(dataStream, image, pngMetaData); } else { - this.DecodePixelData(dataStream, image); + this.DecodePixelData(dataStream, image, pngMetaData); } } @@ -515,7 +493,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The compressed pixel data stream. /// The image to decode to. - private void DecodePixelData(Stream compressedStream, ImageFrame image) + /// The png meta data + private void DecodePixelData(Stream compressedStream, ImageFrame image, PngMetaData pngMetaData) where TPixel : struct, IPixel { while (this.currentRow < this.header.Height) @@ -555,7 +534,7 @@ namespace SixLabors.ImageSharp.Formats.Png throw new ImageFormatException("Unknown filter type."); } - this.ProcessDefilteredScanline(scanlineSpan, image); + this.ProcessDefilteredScanline(scanlineSpan, image, pngMetaData); this.SwapBuffers(); this.currentRow++; @@ -569,7 +548,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The compressed pixel data stream. /// The current image. - private void DecodeInterlacedPixelData(Stream compressedStream, ImageFrame image) + /// The png meta data + private void DecodeInterlacedPixelData(Stream compressedStream, ImageFrame image, PngMetaData pngMetaData) where TPixel : struct, IPixel { while (true) @@ -626,7 +606,7 @@ namespace SixLabors.ImageSharp.Formats.Png } Span rowSpan = image.GetPixelRowSpan(this.currentRow); - this.ProcessInterlacedDefilteredScanline(this.scanline.GetSpan(), rowSpan, Adam7.FirstColumn[this.pass], Adam7.ColumnIncrement[this.pass]); + this.ProcessInterlacedDefilteredScanline(this.scanline.GetSpan(), rowSpan, pngMetaData, Adam7.FirstColumn[this.pass], Adam7.ColumnIncrement[this.pass]); this.SwapBuffers(); @@ -654,7 +634,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The de-filtered scanline /// The image - private void ProcessDefilteredScanline(ReadOnlySpan defilteredScanline, ImageFrame pixels) + /// The png meta data + private void ProcessDefilteredScanline(ReadOnlySpan defilteredScanline, ImageFrame pixels, PngMetaData pngMetaData) where TPixel : struct, IPixel { Span rowSpan = pixels.GetPixelRowSpan(this.currentRow); @@ -674,9 +655,9 @@ namespace SixLabors.ImageSharp.Formats.Png this.header, scanlineSpan, rowSpan, - this.hasTrans, - this.luminance16Trans, - this.luminanceTrans); + pngMetaData.HasTrans, + pngMetaData.Luminance16Trans, + pngMetaData.LuminanceTrans); break; @@ -708,9 +689,9 @@ namespace SixLabors.ImageSharp.Formats.Png rowSpan, this.bytesPerPixel, this.bytesPerSample, - this.hasTrans, - this.rgb48Trans, - this.rgb24Trans); + pngMetaData.HasTrans, + pngMetaData.Rgb48Trans, + pngMetaData.Rgb24Trans); break; @@ -735,9 +716,10 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The de-filtered scanline /// The current image row. + /// The png meta data /// The column start index. Always 0 for none interlaced images. /// The column increment. Always 1 for none interlaced images. - private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defilteredScanline, Span rowSpan, int pixelOffset = 0, int increment = 1) + private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defilteredScanline, Span rowSpan, PngMetaData pngMetaData, int pixelOffset = 0, int increment = 1) where TPixel : struct, IPixel { // Trim the first marker byte from the buffer @@ -757,9 +739,9 @@ namespace SixLabors.ImageSharp.Formats.Png rowSpan, pixelOffset, increment, - this.hasTrans, - this.luminance16Trans, - this.luminanceTrans); + pngMetaData.HasTrans, + pngMetaData.Luminance16Trans, + pngMetaData.LuminanceTrans); break; @@ -796,9 +778,9 @@ namespace SixLabors.ImageSharp.Formats.Png increment, this.bytesPerPixel, this.bytesPerSample, - this.hasTrans, - this.rgb48Trans, - this.rgb24Trans); + pngMetaData.HasTrans, + pngMetaData.Rgb48Trans, + pngMetaData.Rgb24Trans); break; @@ -822,7 +804,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// Decodes and assigns marker colors that identify transparent pixels in non indexed images /// /// The alpha tRNS array - private void AssignTransparentMarkers(ReadOnlySpan alpha) + /// The png meta data + private void AssignTransparentMarkers(ReadOnlySpan alpha, PngMetaData pngMetaData) { if (this.pngColorType == PngColorType.Rgb) { @@ -834,16 +817,16 @@ namespace SixLabors.ImageSharp.Formats.Png 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; + pngMetaData.Rgb48Trans = new Rgb48(rc, gc, bc); + pngMetaData.HasTrans = true; return; } byte r = ReadByteLittleEndian(alpha, 0); byte g = ReadByteLittleEndian(alpha, 2); byte b = ReadByteLittleEndian(alpha, 4); - this.rgb24Trans = new Rgb24(r, g, b); - this.hasTrans = true; + pngMetaData.Rgb24Trans = new Rgb24(r, g, b); + pngMetaData.HasTrans = true; } } else if (this.pngColorType == PngColorType.Grayscale) @@ -852,14 +835,14 @@ namespace SixLabors.ImageSharp.Formats.Png { if (this.header.BitDepth == 16) { - this.luminance16Trans = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(0, 2)); + pngMetaData.Luminance16Trans = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(0, 2)); } else { - this.luminanceTrans = ReadByteLittleEndian(alpha, 0); + pngMetaData.LuminanceTrans = ReadByteLittleEndian(alpha, 0); } - this.hasTrans = true; + pngMetaData.HasTrans = true; } } } diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 7ae716aa05..411d5d69b2 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -290,6 +290,11 @@ namespace SixLabors.ImageSharp.Formats.Png this.WritePaletteChunk(stream, quantized); } + if (pngMetaData.HasTrans) + { + //Write transparency header + } + this.WritePhysicalChunk(stream, metaData); this.WriteGammaChunk(stream); this.WriteExifChunk(stream, metaData); diff --git a/src/ImageSharp/Formats/Png/PngMetaData.cs b/src/ImageSharp/Formats/Png/PngMetaData.cs index 9c76765146..0014defbb9 100644 --- a/src/ImageSharp/Formats/Png/PngMetaData.cs +++ b/src/ImageSharp/Formats/Png/PngMetaData.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.ImageSharp.PixelFormats; + namespace SixLabors.ImageSharp.Formats.Png { /// @@ -42,6 +44,31 @@ namespace SixLabors.ImageSharp.Formats.Png /// public float Gamma { get; set; } + /// + /// Gets or sets the Rgb 24 transparent color. This represents any color in an 8 bit Rgb24 encoded png that should be transparent + /// + public Rgb24 Rgb24Trans { get; set; } + + /// + /// Gets or sets the Rgb 48 transparent color. This represents any color in a 16 bit Rgb24 encoded png that should be transparent + /// + public Rgb48 Rgb48Trans { get; set; } + + /// + /// Gets or sets the 8 bit grayscale transparent color. This represents any color in an 8 bit grayscale encoded png that should be transparent + /// + public byte LuminanceTrans { get; set; } + + /// + /// Gets or sets the 16 bit grayscale transparent color. This represents any color in a 16 bit grayscale encoded png that should be transparent + /// + public ushort Luminance16Trans { get; set; } + + /// + /// Gets or sets a value indicating whether the image has transparency chunk and markers were decoded + /// + public bool HasTrans { get; set; } + /// public IDeepCloneable DeepClone() => new PngMetaData(this); } diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index 73549d98aa..ec9037479b 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.MetaData.Profiles.Icc; +using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.MetaData { From 068b2d3d1ce4ee98546d0be15c79043f46a2ee95 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 31 Oct 2018 00:54:40 +0100 Subject: [PATCH 261/381] results for DecodeJpeg --- .../Codecs/Jpeg/DecodeJpeg.cs | 19 +++++++++++++++++++ .../Codecs/Jpeg/LoadResizeSave.cs | 3 ++- .../ImageSharp.Benchmarks/Samplers/Resize.cs | 4 ++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs index 8eb1fdda6b..2afacb1e4f 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs @@ -57,5 +57,24 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg } } } + + // RESULTS (2018 October): + // + // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 + // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores + // Frequency=2742191 Hz, Resolution=364.6719 ns, Timer=TSC + // .NET Core SDK=2.1.403 + // [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // Job-MCUBGX : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 + // Job-TZIRPF : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // + // + // Method | Runtime | TestImage | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ------------------------------- |-------- |----------------------------- |---------:|----------:|----------:|-------:|---------:|---------:|----------:| + // 'Decode Jpeg - System.Drawing' | Clr | Jpg/baseline/jpeg420exif.jpg | 17.10 ms | 4.720 ms | 0.2667 ms | 1.00 | 0.00 | 218.7500 | 757.88 KB | + // 'Decode Jpeg - ImageSharp' | Clr | Jpg/baseline/jpeg420exif.jpg | 57.77 ms | 4.626 ms | 0.2614 ms | 3.38 | 0.04 | 125.0000 | 566.01 KB | + // | | | | | | | | | | + // 'Decode Jpeg - System.Drawing' | Core | Jpg/baseline/jpeg420exif.jpg | 17.45 ms | 2.092 ms | 0.1182 ms | 1.00 | 0.00 | 218.7500 | 757.04 KB | + // 'Decode Jpeg - ImageSharp' | Core | Jpg/baseline/jpeg420exif.jpg | 48.39 ms | 14.562 ms | 0.8228 ms | 2.77 | 0.04 | 125.0000 | 529.96 KB | } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs index d0d4d569af..72062fc7da 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs @@ -77,7 +77,8 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg } } - // RESULTS: + // RESULTS (2018 October): + // // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores // Frequency=2742191 Hz, Resolution=364.6719 ns, Timer=TSC diff --git a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs index 2be892295e..148b253281 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs @@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.Benchmarks ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic); } - // RESULTS: + // RESULTS (2018 October): // // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores @@ -122,7 +122,7 @@ namespace SixLabors.ImageSharp.Benchmarks ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic, true); } - // RESULTS: + // RESULTS (2018 October): // // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores From e65fc5481f1617de7076f3ced7b54803633e772a Mon Sep 17 00:00:00 2001 From: Devedse Date: Wed, 31 Oct 2018 01:14:09 +0100 Subject: [PATCH 262/381] This should write transparency --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 16 +++--- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 56 ++++++++++++++++++-- src/ImageSharp/Formats/Png/PngMetaData.cs | 8 +-- 3 files changed, 65 insertions(+), 15 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 024bd62216..87c22a2ad6 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -656,8 +656,8 @@ namespace SixLabors.ImageSharp.Formats.Png scanlineSpan, rowSpan, pngMetaData.HasTrans, - pngMetaData.Luminance16Trans, - pngMetaData.LuminanceTrans); + pngMetaData.Luminance16Trans.GetValueOrDefault(), + pngMetaData.LuminanceTrans.GetValueOrDefault()); break; @@ -690,8 +690,8 @@ namespace SixLabors.ImageSharp.Formats.Png this.bytesPerPixel, this.bytesPerSample, pngMetaData.HasTrans, - pngMetaData.Rgb48Trans, - pngMetaData.Rgb24Trans); + pngMetaData.Rgb48Trans.GetValueOrDefault(), + pngMetaData.Rgb24Trans.GetValueOrDefault()); break; @@ -740,8 +740,8 @@ namespace SixLabors.ImageSharp.Formats.Png pixelOffset, increment, pngMetaData.HasTrans, - pngMetaData.Luminance16Trans, - pngMetaData.LuminanceTrans); + pngMetaData.Luminance16Trans.GetValueOrDefault(), + pngMetaData.LuminanceTrans.GetValueOrDefault()); break; @@ -779,8 +779,8 @@ namespace SixLabors.ImageSharp.Formats.Png this.bytesPerPixel, this.bytesPerSample, pngMetaData.HasTrans, - pngMetaData.Rgb48Trans, - pngMetaData.Rgb24Trans); + pngMetaData.Rgb48Trans.GetValueOrDefault(), + pngMetaData.Rgb24Trans.GetValueOrDefault()); break; diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 411d5d69b2..c76dc308bc 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -292,7 +292,7 @@ namespace SixLabors.ImageSharp.Formats.Png if (pngMetaData.HasTrans) { - //Write transparency header + this.WriteTransparencyMarkers(stream, pngMetaData); } this.WritePhysicalChunk(stream, metaData); @@ -305,6 +305,50 @@ namespace SixLabors.ImageSharp.Formats.Png quantized?.Dispose(); } + /// + /// Writes the transparency markers to the stream + /// + /// The containing image data. + /// The image meta data. + private void WriteTransparencyMarkers(Stream stream, PngMetaData pngMetaData) + { + if (pngMetaData.ColorType == PngColorType.Rgb) + { + if (pngMetaData.Rgb48Trans != null) + { + var r = BitConverter.GetBytes(pngMetaData.Rgb48Trans.Value.R); + var g = BitConverter.GetBytes(pngMetaData.Rgb48Trans.Value.R); + var B = BitConverter.GetBytes(pngMetaData.Rgb48Trans.Value.B); + + var alphaArray = r.Concat(g).Concat(B).ToArray(); + + this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); + } + else if (pngMetaData.Rgb24Trans != null) + { + var alphaArray = new byte[6]; + alphaArray[0] = pngMetaData.Rgb24Trans.Value.R; + alphaArray[2] = pngMetaData.Rgb24Trans.Value.G; + alphaArray[4] = pngMetaData.Rgb24Trans.Value.B; + this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); + } + } + else if (pngMetaData.ColorType == PngColorType.Grayscale) + { + if (pngMetaData.Luminance16Trans != null) + { + var alphaArray = BitConverter.GetBytes(pngMetaData.Luminance16Trans.Value); + + this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); + } + else if (pngMetaData.LuminanceTrans != null) + { + var alphaArray = new byte[2]; + alphaArray[0] = pngMetaData.LuminanceTrans.Value; + } + } + } + /// public void Dispose() { @@ -848,7 +892,10 @@ 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. @@ -856,7 +903,10 @@ 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 0014defbb9..765222795a 100644 --- a/src/ImageSharp/Formats/Png/PngMetaData.cs +++ b/src/ImageSharp/Formats/Png/PngMetaData.cs @@ -47,22 +47,22 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Gets or sets the Rgb 24 transparent color. This represents any color in an 8 bit Rgb24 encoded png that should be transparent /// - public Rgb24 Rgb24Trans { get; set; } + public Rgb24? Rgb24Trans { get; set; } /// /// Gets or sets the Rgb 48 transparent color. This represents any color in a 16 bit Rgb24 encoded png that should be transparent /// - public Rgb48 Rgb48Trans { get; set; } + public Rgb48? Rgb48Trans { get; set; } /// /// Gets or sets the 8 bit grayscale transparent color. This represents any color in an 8 bit grayscale encoded png that should be transparent /// - public byte LuminanceTrans { get; set; } + public byte? LuminanceTrans { get; set; } /// /// Gets or sets the 16 bit grayscale transparent color. This represents any color in a 16 bit grayscale encoded png that should be transparent /// - public ushort Luminance16Trans { get; set; } + public ushort? Luminance16Trans { get; set; } /// /// Gets or sets a value indicating whether the image has transparency chunk and markers were decoded From fae06caff766697f82807aed30b4c5fe623b2b39 Mon Sep 17 00:00:00 2001 From: Devedse Date: Wed, 31 Oct 2018 01:27:11 +0100 Subject: [PATCH 263/381] Fixed bug, code now actually fixed my unit test --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index c76dc308bc..edf6cecd7a 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -327,9 +327,9 @@ namespace SixLabors.ImageSharp.Formats.Png else if (pngMetaData.Rgb24Trans != null) { var alphaArray = new byte[6]; - alphaArray[0] = pngMetaData.Rgb24Trans.Value.R; - alphaArray[2] = pngMetaData.Rgb24Trans.Value.G; - alphaArray[4] = pngMetaData.Rgb24Trans.Value.B; + alphaArray[1] = pngMetaData.Rgb24Trans.Value.R; + alphaArray[3] = pngMetaData.Rgb24Trans.Value.G; + alphaArray[5] = pngMetaData.Rgb24Trans.Value.B; this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); } } @@ -344,7 +344,9 @@ namespace SixLabors.ImageSharp.Formats.Png else if (pngMetaData.LuminanceTrans != null) { var alphaArray = new byte[2]; - alphaArray[0] = pngMetaData.LuminanceTrans.Value; + alphaArray[1] = pngMetaData.LuminanceTrans.Value; + + this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); } } } From 099e38a57ba142143d68ac9478534dd60b192ae7 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 31 Oct 2018 01:29:10 +0100 Subject: [PATCH 264/381] drop ComplexIntegrationTests, add ProfilingBenchmarks --- .../ComplexIntegrationTests.cs | 35 ------------- tests/ImageSharp.Tests/ProfilingBenchmarks.cs | 52 +++++++++++++++++++ 2 files changed, 52 insertions(+), 35 deletions(-) delete mode 100644 tests/ImageSharp.Tests/ComplexIntegrationTests.cs create mode 100644 tests/ImageSharp.Tests/ProfilingBenchmarks.cs diff --git a/tests/ImageSharp.Tests/ComplexIntegrationTests.cs b/tests/ImageSharp.Tests/ComplexIntegrationTests.cs deleted file mode 100644 index a260ec33ca..0000000000 --- a/tests/ImageSharp.Tests/ComplexIntegrationTests.cs +++ /dev/null @@ -1,35 +0,0 @@ -using SixLabors.ImageSharp.Formats.Jpeg; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; -using SixLabors.Primitives; - -using Xunit; - -namespace SixLabors.ImageSharp.Tests -{ - /// - /// Might be useful to catch complex bugs - /// - public class ComplexIntegrationTests - { - [Theory] - [WithFile(TestImages.Jpeg.Baseline.Snake, PixelTypes.Rgba32, 75, JpegSubsample.Ratio420)] - [WithFile(TestImages.Jpeg.Baseline.Lake, PixelTypes.Rgba32, 75, JpegSubsample.Ratio420)] - [WithFile(TestImages.Jpeg.Baseline.Snake, PixelTypes.Rgba32, 75, JpegSubsample.Ratio444)] - [WithFile(TestImages.Jpeg.Baseline.Lake, PixelTypes.Rgba32, 75, JpegSubsample.Ratio444)] - public void LoadResizeSave(TestImageProvider provider, int quality, JpegSubsample subsample) - where TPixel : struct, IPixel - { - using (Image image = provider.GetImage(x => x.Resize(new ResizeOptions { Size = new Size(150, 100), Mode = ResizeMode.Max }))) - { - - image.MetaData.ExifProfile = null; // Reduce the size of the file - JpegEncoder options = new JpegEncoder { Subsample = subsample, Quality = quality }; - - provider.Utility.TestName += $"{subsample}_Q{quality}"; - provider.Utility.SaveTestOutputFile(image, "png"); - provider.Utility.SaveTestOutputFile(image, "jpg", options); - } - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks.cs new file mode 100644 index 0000000000..fa873ef859 --- /dev/null +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks.cs @@ -0,0 +1,52 @@ +using System.IO; + +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.Primitives; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests +{ + public class ProfilingBenchmarks : MeasureFixture + { + public const string SkipProfilingTests = +#if false + null; +#else + "Profiling benchmark, enable manually!"; +#endif + + + public ProfilingBenchmarks(ITestOutputHelper output) + : base(output) + { + } + + [Theory(Skip = SkipProfilingTests)] + [InlineData(TestImages.Jpeg.Baseline.Jpeg420Exif)] + public void LoadResizeSave(string imagePath) + { + var configuration = Configuration.CreateDefaultInstance(); + configuration.MaxDegreeOfParallelism = 1; + + byte[] imageBytes = TestFile.Create(imagePath).Bytes; + + using (var ms = new MemoryStream()) + { + this.Measure(30, + () => + { + using (var image = Image.Load(configuration, imageBytes)) + { + image.Mutate(x => x.Resize(image.Size() / 4)); + image.SaveAsJpeg(ms); + } + ms.Seek(0, SeekOrigin.Begin); + }); + } + } + } +} \ No newline at end of file From bd4b78544fa22834221476830fd393514fd40060 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 31 Oct 2018 01:34:13 +0100 Subject: [PATCH 265/381] use InliningOptions.ShortMethod --- .../Formats/Jpeg/Components/Block8x8F.cs | 30 +++++++++---------- .../Jpeg/Components/Decoder/ScanDecoder.cs | 2 +- .../Formats/Jpeg/JpegDecoderCore.cs | 4 +-- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs index 59fc234c42..3a912dc62b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// The float value at the specified index public float this[int idx] { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get { GuardBlockIndex(idx); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components return Unsafe.Add(ref selfRef, idx); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set { GuardBlockIndex(idx); @@ -149,7 +149,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// Fill the block with defaults (zeroes) /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void Clear() { // The cheapest way to do this in C#: @@ -160,7 +160,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Load raw 32bit floating point data from source /// /// Source - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void LoadFrom(Span source) { ref byte s = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); @@ -174,7 +174,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// Block pointer /// Source - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static unsafe void LoadFrom(Block8x8F* blockPtr, Span source) { blockPtr->LoadFrom(source); @@ -200,7 +200,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Copy raw 32bit floating point data to dest /// /// Destination - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void CopyTo(Span dest) { ref byte d = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); @@ -214,7 +214,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components ///
/// Pointer to block /// Destination - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static unsafe void CopyTo(Block8x8F* blockPtr, Span dest) { float* fPtr = (float*)blockPtr; @@ -230,7 +230,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components ///
/// Block pointer /// Destination - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static unsafe void CopyTo(Block8x8F* blockPtr, Span dest) { blockPtr->CopyTo(dest); @@ -240,7 +240,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Copy raw 32bit floating point data to dest ///
/// Destination - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public unsafe void CopyTo(float[] dest) { fixed (void* ptr = &this.V0L) @@ -276,7 +276,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Multiply all elements of the block. ///
/// The value to multiply by - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void MultiplyInplace(float value) { this.V0L *= value; @@ -300,7 +300,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// Multiply all elements of the block by the corresponding elements of 'other' /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void MultiplyInplace(ref Block8x8F other) { this.V0L *= other.V0L; @@ -325,7 +325,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Adds a vector to all elements of the block. ///
/// The added vector - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void AddToAllInplace(Vector4 diff) { this.V0L += diff; @@ -420,7 +420,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static void DivideRoundAll(ref Block8x8F a, ref Block8x8F b) { a.V0L = DivideRound(a.V0L, b.V0L); @@ -511,7 +511,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components return sb.ToString(); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static Vector NormalizeAndRound(Vector row, Vector off, Vector max) { row += off; @@ -520,7 +520,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components return row.FastRound(); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static Vector4 DivideRound(Vector4 dividend, Vector4 divisor) { // sign(dividend) = max(min(dividend, 1), -1) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs index 351e453484..39b9792ac9 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs @@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static uint LRot(uint x, int y) => (x << y) | (x >> (32 - y)); private void ParseBaselineData() diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 36246c6820..68252f624c 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -913,7 +913,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// The table index /// The codelengths /// The values - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void BuildHuffmanTable(HuffmanTables tables, int index, ReadOnlySpan codeLengths, ReadOnlySpan values) => tables[index] = new HuffmanTable(this.configuration.MemoryAllocator, codeLengths, values); @@ -921,7 +921,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// Reads a from the stream advancing it by two bytes ///
/// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private ushort ReadUint16() { this.InputStream.Read(this.markerBuffer, 0, 2); From 02a8d0ddc185979175a4af170bc43e88bc493807 Mon Sep 17 00:00:00 2001 From: Devedse <2350015+devedse@users.noreply.github.com> Date: Wed, 31 Oct 2018 02:04:59 +0100 Subject: [PATCH 266/381] Update PngEncoderCore.cs Lowercase b --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index edf6cecd7a..1179a6db31 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -318,9 +318,9 @@ namespace SixLabors.ImageSharp.Formats.Png { var r = BitConverter.GetBytes(pngMetaData.Rgb48Trans.Value.R); var g = BitConverter.GetBytes(pngMetaData.Rgb48Trans.Value.R); - var B = BitConverter.GetBytes(pngMetaData.Rgb48Trans.Value.B); + var b = BitConverter.GetBytes(pngMetaData.Rgb48Trans.Value.B); - var alphaArray = r.Concat(g).Concat(B).ToArray(); + var alphaArray = r.Concat(g).Concat(b).ToArray(); this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); } @@ -1004,4 +1004,4 @@ namespace SixLabors.ImageSharp.Formats.Png return scanlineLength / mod; } } -} \ No newline at end of file +} From b2920a12ba89334acf20d3f89865cc0ac66753bc Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 31 Oct 2018 18:00:11 +0000 Subject: [PATCH 267/381] Don't force transparency --- .../PixelFormats/NamedColors{TPixel}.cs | 5 +--- src/ImageSharp/Processing/KnownQuantizers.cs | 4 --- .../Quantization/QuantizedImageTests.cs | 25 ------------------- tests/Images/External | 2 +- 4 files changed, 2 insertions(+), 34 deletions(-) diff --git a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs index a757a393ef..7e093de042 100644 --- a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs @@ -746,10 +746,7 @@ namespace SixLabors.ImageSharp.PixelFormats private static TPixel[] GetPalette(Rgba32[] palette) { - // TODO: This should be the length only. - // We need to fix and update tests/reference images. - // If someone wants transparency they should add it to the palette. - var converted = new TPixel[palette.Length + 1]; + var converted = new TPixel[palette.Length]; Span constantsBytes = MemoryMarshal.Cast(palette.AsSpan()); PixelOperations.Instance.FromRgba32Bytes( diff --git a/src/ImageSharp/Processing/KnownQuantizers.cs b/src/ImageSharp/Processing/KnownQuantizers.cs index e93a9921a9..e4a7a75d5f 100644 --- a/src/ImageSharp/Processing/KnownQuantizers.cs +++ b/src/ImageSharp/Processing/KnownQuantizers.cs @@ -12,26 +12,22 @@ namespace SixLabors.ImageSharp.Processing { /// /// Gets the adaptive Octree quantizer. Fast with good quality. - /// The quantizer only supports a single alpha value. /// public static IQuantizer Octree { get; } = new OctreeQuantizer(); /// /// Gets the Xiaolin Wu's Color Quantizer which generates high quality output. - /// The quantizer supports multiple alpha values. /// public static IQuantizer Wu { get; } = new WuQuantizer(); /// /// Gets the palette based quantizer consisting of web safe colors as defined in the CSS Color Module Level 4. - /// The quantizer supports a single alpha value. /// public static IQuantizer WebSafe { get; } = new WebSafePaletteQuantizer(); /// /// Gets the palette based quantizer consisting of colors as defined in the original second edition of Werner’s Nomenclature of Colours 1821. /// The hex codes were collected and defined by Nicholas Rougeux - /// The quantizer supports a single alpha value. /// public static IQuantizer Werner { get; } = new WernerPaletteQuantizer(); } diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index 753c2c109c..a0d7869e39 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -31,31 +31,6 @@ namespace SixLabors.ImageSharp.Tests Assert.True(wu.CreateFrameQuantizer(this.Configuration).Dither); } - [Theory] - [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, true)] - [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, false)] - public void PaletteQuantizerYieldsCorrectTransparentPixel( - TestImageProvider provider, - bool dither) - where TPixel : struct, IPixel - { - using (Image image = provider.GetImage()) - { - Assert.True(image[0, 0].Equals(default(TPixel))); - - var quantizer = new WebSafePaletteQuantizer(dither); - - foreach (ImageFrame frame in image.Frames) - { - QuantizedFrame quantized = - quantizer.CreateFrameQuantizer(this.Configuration).QuantizeFrame(frame); - - int index = this.GetTransparentIndex(quantized); - Assert.Equal(index, quantized.GetPixelSpan()[0]); - } - } - } - [Theory] [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, true)] [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, false)] diff --git a/tests/Images/External b/tests/Images/External index f41ae0327a..ed8a7b0b6f 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit f41ae0327a3ab21ab2388c32160bda67debcc082 +Subproject commit ed8a7b0b6fe1b2e2a7c822aa617103ae31192655 From b5e419d89ee76ee256822273068a70978f181124 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 1 Nov 2018 14:16:53 +0100 Subject: [PATCH 268/381] InliningOptions.ShortMethod --- .../Formats/Jpeg/Components/Block8x8F.Generated.cs | 4 ++-- .../Formats/Jpeg/Components/Block8x8F.Generated.tt | 4 ++-- .../Formats/Jpg/JpegProfilingBenchmarks.cs | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs index e83896f587..53f29734c5 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Transpose the block into the destination block. ///
/// The destination block - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void TransposeInto(ref Block8x8F d) { d.V0L.X = V0L.X; @@ -119,7 +119,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// AVX2-only variant for executing and in one step. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void NormalizeColorsAndRoundInplaceAvx2() { Vector off = new Vector(128f); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt index 82d82ef0c2..76c61f6c35 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Transpose the block into the destination block. ///
/// The destination block - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void TransposeInto(ref Block8x8F d) { <# @@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// AVX2-only variant for executing and in one step. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void NormalizeColorsAndRoundInplaceAvx2() { Vector off = new Vector(128f); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs index 32538090dc..f60f478e1a 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs @@ -24,21 +24,21 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public static readonly TheoryData DecodeJpegData = new TheoryData() { - TestImages.Jpeg.Baseline.Cmyk, - TestImages.Jpeg.Baseline.Ycck, + //TestImages.Jpeg.Baseline.Cmyk, + //TestImages.Jpeg.Baseline.Ycck, TestImages.Jpeg.Baseline.Calliphora, TestImages.Jpeg.Baseline.Jpeg400, TestImages.Jpeg.Baseline.Jpeg420Exif, TestImages.Jpeg.Baseline.Jpeg444, }; - // [Theory] // Benchmark, enable manually - // [MemberData(nameof(DecodeJpegData))] + [Theory] // Benchmark, enable manually + [MemberData(nameof(DecodeJpegData))] public void DecodeJpeg(string fileName) { this.DecodeJpegBenchmarkImpl(fileName, new JpegDecoder()); } - + private void DecodeJpegBenchmarkImpl(string fileName, IImageDecoder decoder) { // do not run this on CI even by accident From af5e0138d5c0cd649b5f57e0c374bfbcf6b6a5d2 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 1 Nov 2018 14:21:42 +0000 Subject: [PATCH 269/381] Change tolerance for Net462 --- tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index a98ae164a1..b74a7a85f9 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif public class GifEncoderTests { private const PixelTypes TestPixelTypes = PixelTypes.Rgba32 | PixelTypes.RgbaVector | PixelTypes.Argb32; - private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.001F); + private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.0015F); public static readonly TheoryData RatioFiles = new TheoryData From 7f113ab00a03bca62b48499db366d17f68809f4d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 1 Nov 2018 16:00:17 +0100 Subject: [PATCH 270/381] AVX2 optimized Block8x8 -> Block8x8F conversion --- src/ImageSharp/Common/Helpers/DebugGuard.cs | 14 ++++++ .../Common/Helpers/InliningOptions.cs | 2 +- .../Helpers/SimdUtils.ExtendedIntrinsics.cs | 14 ++++++ .../Jpeg/Components/Block8x8F.Generated.cs | 2 +- .../Jpeg/Components/Block8x8F.Generated.tt | 2 +- .../Formats/Jpeg/Components/Block8x8F.cs | 45 +++++++++++++++++++ .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 21 +++++++++ .../Formats/Jpg/Block8x8FTests.cs | 42 +++++++++++++++++ .../Formats/Jpg/JpegProfilingBenchmarks.cs | 4 +- .../Formats/Jpg/Utils/JpegFixture.cs | 7 ++- tests/ImageSharp.Tests/ProfilingBenchmarks.cs | 2 +- .../TestUtilities/TestDataGenerator.cs | 11 +++++ 12 files changed, 159 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/DebugGuard.cs b/src/ImageSharp/Common/Helpers/DebugGuard.cs index 2cf18b2456..43eebeac87 100644 --- a/src/ImageSharp/Common/Helpers/DebugGuard.cs +++ b/src/ImageSharp/Common/Helpers/DebugGuard.cs @@ -163,6 +163,20 @@ namespace SixLabors.ImageSharp } } + /// + /// Verifies whether a specific condition is met, throwing an exception if it's false. + /// + /// The condition + /// The error message + [Conditional("DEBUG")] + public static void IsTrue(bool target, string message) + { + if (!target) + { + throw new InvalidOperationException(message); + } + } + /// /// Verifies, that the method parameter with specified target value is false /// and throws an exception if it is found to be so. diff --git a/src/ImageSharp/Common/Helpers/InliningOptions.cs b/src/ImageSharp/Common/Helpers/InliningOptions.cs index ad85c4fc81..f61e4f8aef 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/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index 2ac577264c..463961d868 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -25,6 +25,20 @@ namespace SixLabors.ImageSharp false; #endif + /// + /// Widen and convert a vector of values into 2 vectors of -s. + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void ConvertToSingle( + Vector source, + out Vector dest1, + out Vector dest2) + { + Vector.Widen(source, out Vector i1, out Vector i2); + dest1 = Vector.ConvertToSingle(i1); + dest2 = Vector.ConvertToSingle(i2); + } + /// /// as many elements as possible, slicing them down (keeping the remainder). /// diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs index 53f29734c5..09ed6408d7 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs @@ -154,7 +154,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// Fill the block from 'source' doing short -> float conversion. /// - public void LoadFrom(ref Block8x8 source) + public void LoadFromInt16Scalar(ref Block8x8 source) { ref short selfRef = ref Unsafe.As(ref source); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt index 76c61f6c35..f93ee6522d 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// Fill the block from 'source' doing short -> float conversion. /// - public void LoadFrom(ref Block8x8 source) + public void LoadFromInt16Scalar(ref Block8x8 source) { ref short selfRef = ref Unsafe.As(ref source); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs index 3a912dc62b..137a8029d8 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs @@ -493,6 +493,51 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components } } + [MethodImpl(InliningOptions.ShortMethod)] + public void LoadFrom(ref Block8x8 source) + { +#if SUPPORTS_EXTENDED_INTRINSICS + if (SimdUtils.IsAvx2CompatibleArchitecture) + { + this.LoadFromInt16ExtendedAvx2(ref source); + return; + } +#endif + this.LoadFromInt16Scalar(ref source); + } + + /// + /// Loads values from using extended AVX2 intrinsics. + /// + /// The source + public void LoadFromInt16ExtendedAvx2(ref Block8x8 source) + { + DebugGuard.IsTrue( + SimdUtils.IsAvx2CompatibleArchitecture, + "LoadFromUInt16ExtendedAvx2 only works on AVX2 compatible architecture!"); + + ref Vector sRef = ref Unsafe.As>(ref source); + ref Vector dRef = ref Unsafe.As>(ref this); + + // Vector.Count == 16 on AVX2 + // We can process 2 block rows in a single step + SimdUtils.ExtendedIntrinsics.ConvertToSingle(sRef, out Vector top, out Vector bottom); + dRef = top; + Unsafe.Add(ref dRef, 1) = bottom; + + SimdUtils.ExtendedIntrinsics.ConvertToSingle(Unsafe.Add(ref sRef, 1), out top, out bottom); + Unsafe.Add(ref dRef, 2) = top; + Unsafe.Add(ref dRef, 3) = bottom; + + SimdUtils.ExtendedIntrinsics.ConvertToSingle(Unsafe.Add(ref sRef, 2), out top, out bottom); + Unsafe.Add(ref dRef, 4) = top; + Unsafe.Add(ref dRef, 5) = bottom; + + SimdUtils.ExtendedIntrinsics.ConvertToSingle(Unsafe.Add(ref sRef, 3), out top, out bottom); + Unsafe.Add(ref dRef, 6) = top; + Unsafe.Add(ref dRef, 7) = bottom; + } + /// public override string ToString() { diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index c63cb3438f..4f8a2cdaf7 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -257,6 +257,27 @@ namespace SixLabors.ImageSharp.Tests.Common ); } + [Theory] + [InlineData(1234)] + public void ExtendedIntrinsics_ConvertToSingle(short scale) + { + int n = Vector.Count; + short[] sData = new Random(scale).GenerateRandomInt16Array(2 * n, (short)-scale, scale); + float[] fData = sData.Select(u => (float)u).ToArray(); + + var source = new Vector(sData); + + var expected1 = new Vector(fData, 0); + var expected2 = new Vector(fData, n); + + // Act: + SimdUtils.ExtendedIntrinsics.ConvertToSingle(source, out Vector actual1, out Vector actual2); + + // Assert: + Assert.Equal(expected1, actual1); + Assert.Equal(expected2, actual2); + } + [Theory] [MemberData(nameof(ArbitraryArraySizes))] public void BulkConvertNormalizedFloatToByteClampOverflows(int count) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs index e72f4945b7..81c76390c1 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs @@ -408,5 +408,47 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg Assert.Equal(original[i] * 42f, actual[i]); } } + + [Fact] + public void LoadFromUInt16Scalar() + { + if (this.SkipOnNonAvx2Runner()) + { + return; + } + + short[] data = Create8x8ShortData(); + + var source = new Block8x8(data); + + Block8x8F dest = default; + dest.LoadFromInt16Scalar(ref source); + + for (int i = 0; i < Block8x8F.Size; i++) + { + Assert.Equal((float)data[i], dest[i]); + } + } + + [Fact] + public void LoadFromUInt16ExtendedAvx2() + { + if (this.SkipOnNonAvx2Runner()) + { + return; + } + + short[] data = Create8x8ShortData(); + + var source = new Block8x8(data); + + Block8x8F dest = default; + dest.LoadFromInt16ExtendedAvx2(ref source); + + for (int i = 0; i < Block8x8F.Size; i++) + { + Assert.Equal((float)data[i], dest[i]); + } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs index f60f478e1a..7d5130e1bc 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs @@ -32,8 +32,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Baseline.Jpeg444, }; - [Theory] // Benchmark, enable manually - [MemberData(nameof(DecodeJpegData))] + //[Theory] // Benchmark, enable manually + //[MemberData(nameof(DecodeJpegData))] public void DecodeJpeg(string fileName) { this.DecodeJpegBenchmarkImpl(fileName, new JpegDecoder()); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs index d14fbc3fc3..89fdd5745e 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs @@ -58,7 +58,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils { for (int j = 0; j < 8; j++) { - result[i * 8 + j] = (short)(i * 10 + j); + short val = (short)(i * 10 + j); + if ((i + j) % 2 == 0) + { + val *= -1; + } + result[i * 8 + j] = val; } } return result; diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks.cs index fa873ef859..bc9b2a947b 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Tests public class ProfilingBenchmarks : MeasureFixture { public const string SkipProfilingTests = -#if false +#if true null; #else "Profiling benchmark, enable manually!"; diff --git a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs index 56cde41fc1..e3d8bf3806 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs @@ -88,6 +88,17 @@ namespace SixLabors.ImageSharp.Tests return values; } + public static short[] GenerateRandomInt16Array(this Random rnd, int length, short minVal, short maxVal) + { + short[] values = new short[length]; + for (int i = 0; i < values.Length; i++) + { + values[i] = (short)rnd.Next(minVal, maxVal); + } + + return values; + } + private static float GetRandomFloat(this Random rnd, float minVal, float maxVal) => ((float)rnd.NextDouble() * (maxVal - minVal)) + minVal; } } \ No newline at end of file From 2acf80ea163a5eeb98daac9e5d9d6a4f0f6523ef Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 2 Nov 2018 00:36:04 +0100 Subject: [PATCH 271/381] Moved IJpegComponent.GetBlockReference(...) to an extension method --- .../Jpeg/Components/Decoder/IJpegComponent.cs | 11 +----- .../Jpeg/Components/Decoder/JpegComponent.cs | 18 ++------- .../Decoder/JpegComponentExtensions.cs | 39 +++++++++++++++++++ 3 files changed, 44 insertions(+), 24 deletions(-) create mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentExtensions.cs diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs index c033980336..2492a985a8 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.Memory; -using SixLabors.Memory; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder @@ -43,16 +42,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// /// Gets the storing the "raw" frequency-domain decoded + unzigged blocks. - /// We need to apply IDCT and dequantiazition to transform them into color-space blocks. + /// We need to apply IDCT and dequantization to transform them into color-space blocks. /// Buffer2D SpectralBlocks { get; } - - /// - /// Gets a reference to the at the given row and column index from - /// - /// The column - /// The row - /// The - ref Block8x8 GetBlockReference(int column, int row); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs index 65a584c4f2..ef03582d69 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs @@ -128,21 +128,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder this.SubSamplingDivisors = c0.SamplingFactors.DivideBy(this.SamplingFactors); } - this.SpectralBlocks = this.memoryAllocator.Allocate2D(blocksPerColumnForMcu, blocksPerLineForMcu + 1, AllocationOptions.Clean); - } + int totalNumberOfBlocks = blocksPerColumnForMcu * (blocksPerLineForMcu + 1); + int width = this.WidthInBlocks + 1; + int height = totalNumberOfBlocks / width; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref Block8x8 GetBlockReference(int column, int row) - { - int offset = ((this.WidthInBlocks + 1) * row) + column; - return ref Unsafe.Add(ref MemoryMarshal.GetReference(this.SpectralBlocks.GetSpan()), offset); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref short GetBlockDataReference(int column, int row) - { - ref Block8x8 blockRef = ref this.GetBlockReference(column, row); - return ref Unsafe.As(ref blockRef); + this.SpectralBlocks = this.memoryAllocator.Allocate2D(width, height, AllocationOptions.Clean); } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentExtensions.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentExtensions.cs new file mode 100644 index 0000000000..d7fb52a790 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentExtensions.cs @@ -0,0 +1,39 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Runtime.CompilerServices; + +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder +{ + /// + /// Extension methods for + /// + internal static class JpegComponentExtensions + { + /// + /// Gets a reference to the at the given row and column index from + /// + /// The + /// The column + /// The row + /// The + [MethodImpl(InliningOptions.ShortMethod)] + public static ref Block8x8 GetBlockReference(this IJpegComponent component, int column, int row) + { + return ref component.SpectralBlocks.GetRowSpan(row)[column]; + } + + /// + /// Gets a reference to the first item in a block + /// at the given row and column index from + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static ref short GetBlockDataReference(this IJpegComponent component, int column, int row) + { + ref Block8x8 blockRef = ref component.GetBlockReference(column, row); + return ref Unsafe.As(ref blockRef); + } + } +} \ No newline at end of file From aa35af70953503a95e6dbb0d16ab7b5b70935970 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 2 Nov 2018 00:45:25 +0100 Subject: [PATCH 272/381] do not use GetBlockReference() on hot path --- .../Decoder/JpegComponentPostProcessor.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs index 890f402595..57a53549f5 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs @@ -2,6 +2,8 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory; using SixLabors.Memory; @@ -88,12 +90,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder int yBuffer = y * this.blockAreaSize.Height; - for (int x = 0; x < this.SizeInBlocks.Width; x++) - { - int xBlock = x; - int xBuffer = x * this.blockAreaSize.Width; + Span blockRow = this.Component.SpectralBlocks.GetRowSpan(yBlock); + + ref Block8x8 blockRowBase = ref MemoryMarshal.GetReference(blockRow); - ref Block8x8 block = ref this.Component.GetBlockReference(xBlock, yBlock); + for (int xBlock = 0; xBlock < this.SizeInBlocks.Width; xBlock++) + { + ref Block8x8 block = ref Unsafe.Add(ref blockRowBase, xBlock); + int xBuffer = xBlock * this.blockAreaSize.Width; BufferArea destArea = this.ColorBuffer.GetArea( xBuffer, From a7aef83dcceb7d291b7bed81277e675be2d65ca7 Mon Sep 17 00:00:00 2001 From: Devedse Date: Fri, 2 Nov 2018 17:36:38 +0100 Subject: [PATCH 273/381] Removed unused using --- src/ImageSharp/MetaData/ImageMetaData.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index ec9037479b..73549d98aa 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.MetaData.Profiles.Icc; -using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.MetaData { From 6364b502da9aed140aa8430ccdddb148acf6efd3 Mon Sep 17 00:00:00 2001 From: Devedse Date: Fri, 2 Nov 2018 17:49:35 +0100 Subject: [PATCH 274/381] Resolved findings in PR --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 24 +++++++++---------- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 24 +++++++++---------- src/ImageSharp/Formats/Png/PngMetaData.cs | 8 +++---- .../Formats/Png/PngScanlineProcessor.cs | 16 ++++++------- 4 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 87c22a2ad6..c446184d80 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -656,8 +656,8 @@ namespace SixLabors.ImageSharp.Formats.Png scanlineSpan, rowSpan, pngMetaData.HasTrans, - pngMetaData.Luminance16Trans.GetValueOrDefault(), - pngMetaData.LuminanceTrans.GetValueOrDefault()); + pngMetaData.TransparentGray16.GetValueOrDefault(), + pngMetaData.TransparentGray8.GetValueOrDefault()); break; @@ -690,8 +690,8 @@ namespace SixLabors.ImageSharp.Formats.Png this.bytesPerPixel, this.bytesPerSample, pngMetaData.HasTrans, - pngMetaData.Rgb48Trans.GetValueOrDefault(), - pngMetaData.Rgb24Trans.GetValueOrDefault()); + pngMetaData.TransparentRgb48.GetValueOrDefault(), + pngMetaData.TransparentRgb24.GetValueOrDefault()); break; @@ -740,8 +740,8 @@ namespace SixLabors.ImageSharp.Formats.Png pixelOffset, increment, pngMetaData.HasTrans, - pngMetaData.Luminance16Trans.GetValueOrDefault(), - pngMetaData.LuminanceTrans.GetValueOrDefault()); + pngMetaData.TransparentGray16.GetValueOrDefault(), + pngMetaData.TransparentGray8.GetValueOrDefault()); break; @@ -779,8 +779,8 @@ namespace SixLabors.ImageSharp.Formats.Png this.bytesPerPixel, this.bytesPerSample, pngMetaData.HasTrans, - pngMetaData.Rgb48Trans.GetValueOrDefault(), - pngMetaData.Rgb24Trans.GetValueOrDefault()); + pngMetaData.TransparentRgb48.GetValueOrDefault(), + pngMetaData.TransparentRgb24.GetValueOrDefault()); break; @@ -817,7 +817,7 @@ namespace SixLabors.ImageSharp.Formats.Png ushort gc = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(2, 2)); ushort bc = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(4, 2)); - pngMetaData.Rgb48Trans = new Rgb48(rc, gc, bc); + pngMetaData.TransparentRgb48 = new Rgb48(rc, gc, bc); pngMetaData.HasTrans = true; return; } @@ -825,7 +825,7 @@ namespace SixLabors.ImageSharp.Formats.Png byte r = ReadByteLittleEndian(alpha, 0); byte g = ReadByteLittleEndian(alpha, 2); byte b = ReadByteLittleEndian(alpha, 4); - pngMetaData.Rgb24Trans = new Rgb24(r, g, b); + pngMetaData.TransparentRgb24 = new Rgb24(r, g, b); pngMetaData.HasTrans = true; } } @@ -835,11 +835,11 @@ namespace SixLabors.ImageSharp.Formats.Png { if (this.header.BitDepth == 16) { - pngMetaData.Luminance16Trans = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(0, 2)); + pngMetaData.TransparentGray16 = new Gray16(BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(0, 2))); } else { - pngMetaData.LuminanceTrans = ReadByteLittleEndian(alpha, 0); + pngMetaData.TransparentGray8 = new Gray8(ReadByteLittleEndian(alpha, 0)); } pngMetaData.HasTrans = true; diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 1179a6db31..e953bc1f07 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -314,37 +314,37 @@ namespace SixLabors.ImageSharp.Formats.Png { if (pngMetaData.ColorType == PngColorType.Rgb) { - if (pngMetaData.Rgb48Trans != null) + if (pngMetaData.TransparentRgb48 != null) { - var r = BitConverter.GetBytes(pngMetaData.Rgb48Trans.Value.R); - var g = BitConverter.GetBytes(pngMetaData.Rgb48Trans.Value.R); - var b = BitConverter.GetBytes(pngMetaData.Rgb48Trans.Value.B); + var r = BitConverter.GetBytes(pngMetaData.TransparentRgb48.Value.R); + var g = BitConverter.GetBytes(pngMetaData.TransparentRgb48.Value.R); + var b = BitConverter.GetBytes(pngMetaData.TransparentRgb48.Value.B); var alphaArray = r.Concat(g).Concat(b).ToArray(); this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); } - else if (pngMetaData.Rgb24Trans != null) + else if (pngMetaData.TransparentRgb24 != null) { var alphaArray = new byte[6]; - alphaArray[1] = pngMetaData.Rgb24Trans.Value.R; - alphaArray[3] = pngMetaData.Rgb24Trans.Value.G; - alphaArray[5] = pngMetaData.Rgb24Trans.Value.B; + alphaArray[1] = pngMetaData.TransparentRgb24.Value.R; + alphaArray[3] = pngMetaData.TransparentRgb24.Value.G; + alphaArray[5] = pngMetaData.TransparentRgb24.Value.B; this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); } } else if (pngMetaData.ColorType == PngColorType.Grayscale) { - if (pngMetaData.Luminance16Trans != null) + if (pngMetaData.TransparentGray16 != null) { - var alphaArray = BitConverter.GetBytes(pngMetaData.Luminance16Trans.Value); + var alphaArray = BitConverter.GetBytes(pngMetaData.TransparentGray16.Value.PackedValue); this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); } - else if (pngMetaData.LuminanceTrans != null) + else if (pngMetaData.TransparentGray8 != null) { var alphaArray = new byte[2]; - alphaArray[1] = pngMetaData.LuminanceTrans.Value; + alphaArray[1] = pngMetaData.TransparentGray8.Value.PackedValue; this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); } diff --git a/src/ImageSharp/Formats/Png/PngMetaData.cs b/src/ImageSharp/Formats/Png/PngMetaData.cs index 765222795a..6a293f770c 100644 --- a/src/ImageSharp/Formats/Png/PngMetaData.cs +++ b/src/ImageSharp/Formats/Png/PngMetaData.cs @@ -47,22 +47,22 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Gets or sets the Rgb 24 transparent color. This represents any color in an 8 bit Rgb24 encoded png that should be transparent /// - public Rgb24? Rgb24Trans { get; set; } + public Rgb24? TransparentRgb24 { get; set; } /// /// Gets or sets the Rgb 48 transparent color. This represents any color in a 16 bit Rgb24 encoded png that should be transparent /// - public Rgb48? Rgb48Trans { get; set; } + public Rgb48? TransparentRgb48 { get; set; } /// /// Gets or sets the 8 bit grayscale transparent color. This represents any color in an 8 bit grayscale encoded png that should be transparent /// - public byte? LuminanceTrans { get; set; } + public Gray8? TransparentGray8 { get; set; } /// /// Gets or sets the 16 bit grayscale transparent color. This represents any color in a 16 bit grayscale encoded png that should be transparent /// - public ushort? Luminance16Trans { get; set; } + public Gray16? TransparentGray16 { get; set; } /// /// Gets or sets a value indicating whether the image has transparency chunk and markers were decoded diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index 3fe590ee24..528c012c58 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -20,8 +20,8 @@ namespace SixLabors.ImageSharp.Formats.Png ReadOnlySpan scanlineSpan, Span rowSpan, bool hasTrans, - ushort luminance16Trans, - byte luminanceTrans) + Gray16 luminance16Trans, + Gray8 luminanceTrans) where TPixel : struct, IPixel { TPixel pixel = default; @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.R = luminance; rgba64.G = luminance; rgba64.B = luminance; - rgba64.A = luminance.Equals(luminance16Trans) ? ushort.MinValue : ushort.MaxValue; + rgba64.A = luminance.Equals(luminance16Trans.PackedValue) ? ushort.MinValue : ushort.MaxValue; pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - byte scaledLuminanceTrans = (byte)(luminanceTrans * scaleFactor); + byte scaledLuminanceTrans = (byte)(luminanceTrans.PackedValue * scaleFactor); Rgba32 rgba32 = default; for (int x = 0; x < header.Width; x++) { @@ -93,8 +93,8 @@ namespace SixLabors.ImageSharp.Formats.Png int pixelOffset, int increment, bool hasTrans, - ushort luminance16Trans, - byte luminanceTrans) + Gray16 luminance16Trans, + Gray8 luminanceTrans) where TPixel : struct, IPixel { TPixel pixel = default; @@ -135,7 +135,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.R = luminance; rgba64.G = luminance; rgba64.B = luminance; - rgba64.A = luminance.Equals(luminance16Trans) ? ushort.MinValue : ushort.MaxValue; + rgba64.A = luminance.Equals(luminance16Trans.PackedValue) ? ushort.MinValue : ushort.MaxValue; pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; @@ -143,7 +143,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - byte scaledLuminanceTrans = (byte)(luminanceTrans * scaleFactor); + byte scaledLuminanceTrans = (byte)(luminanceTrans.PackedValue * scaleFactor); Rgba32 rgba32 = default; for (int x = pixelOffset; x < header.Width; x += increment) { From 5162e6b68c087a0553ee559eaa8b213c26e39402 Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Fri, 2 Nov 2018 17:08:20 -0500 Subject: [PATCH 275/381] ImageSharp-762: Added methods to pre-seed AoT compiler on iOS --- src/ImageSharp/Formats/Gif/ImageExtensions.cs | 19 +++++++++++++++++++ .../OctreeFrameQuantizer{TPixel}.cs | 2 ++ 2 files changed, 21 insertions(+) diff --git a/src/ImageSharp/Formats/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs index 8ddd4247e1..b226201082 100644 --- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs @@ -5,6 +5,7 @@ using System.IO; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Quantization; namespace SixLabors.ImageSharp { @@ -35,5 +36,23 @@ namespace SixLabors.ImageSharp public static void SaveAsGif(this Image source, Stream stream, GifEncoder encoder) where TPixel : struct, IPixel => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(GifFormat.Instance)); + + /// + /// This method doesn't actually do anything but serves an important purpose... + /// If you are running ImageSharp on iOS and try to call SaveAsGif, it will throw an excepion: + /// "Attempting to JIT compile method... OctreeFrameQuantizer.ConstructPalette... while running in aot-only mode." + /// The reason this happens is the SaveAsGif method makes haevy use of generics, which are too confusing for the AoT + /// compiler used on Xamarin.iOS. It spins up the JIT compiler to try and figure it out, but that is an illegal op on + /// iOS so it bombs out. + /// If you are getting the above error, you need to call this method, which will pre-seed the AoT compiler with the + /// necessary methods to complete the SaveAsGif call. That's it, otherwise you should NEVER need this method!!! + /// + /// The pixel format. + public static void AotCompileOctreeQuantizer() + where TPixel : struct, IPixel + { + var test = new OctreeFrameQuantizer(new OctreeQuantizer(false)); + test.AotGetPalette(); + } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs index 1eeb0be410..8f688e8387 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs @@ -136,6 +136,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } } + internal TPixel[] AotGetPalette() => this.octree.Palletize(this.colors); + /// protected override TPixel[] GetPalette() => this.octree.Palletize(this.colors); From 265f27913c5134cd2de0ad015ca484183254474e Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 3 Nov 2018 00:19:09 +0100 Subject: [PATCH 276/381] benchmarks for current state --- .../Common/Helpers/InliningOptions.cs | 2 +- .../Helpers/SimdUtils.ExtendedIntrinsics.cs | 2 +- .../Codecs/Jpeg/DecodeJpeg.cs | 9 ++++ .../General/Block8x8F_LoadFromInt16.cs | 48 +++++++++++++++++++ 4 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 tests/ImageSharp.Benchmarks/General/Block8x8F_LoadFromInt16.cs diff --git a/src/ImageSharp/Common/Helpers/InliningOptions.cs b/src/ImageSharp/Common/Helpers/InliningOptions.cs index f61e4f8aef..ad85c4fc81 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/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index 463961d868..9aeb209319 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp /// /// Widen and convert a vector of values into 2 vectors of -s. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void ConvertToSingle( Vector source, out Vector dest1, diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs index 2afacb1e4f..57dcede88d 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs @@ -76,5 +76,14 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg // | | | | | | | | | | // 'Decode Jpeg - System.Drawing' | Core | Jpg/baseline/jpeg420exif.jpg | 17.45 ms | 2.092 ms | 0.1182 ms | 1.00 | 0.00 | 218.7500 | 757.04 KB | // 'Decode Jpeg - ImageSharp' | Core | Jpg/baseline/jpeg420exif.jpg | 48.39 ms | 14.562 ms | 0.8228 ms | 2.77 | 0.04 | 125.0000 | 529.96 KB | + + // RESULTS (2018 November 1): + // Method | Runtime | TestImage | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ------------------------------- |-------- |----------------------------- |---------:|----------:|----------:|-------:|---------:|---------:|----------:| + // 'Decode Jpeg - System.Drawing' | Clr | Jpg/baseline/jpeg420exif.jpg | 17.59 ms | 4.611 ms | 0.2605 ms | 1.00 | 0.00 | 218.7500 | 757.88 KB | + // 'Decode Jpeg - ImageSharp' | Clr | Jpg/baseline/jpeg420exif.jpg | 55.33 ms | 2.133 ms | 0.1205 ms | 3.15 | 0.04 | 125.0000 | 566.01 KB | + // | | | | | | | | | | + // 'Decode Jpeg - System.Drawing' | Core | Jpg/baseline/jpeg420exif.jpg | 17.83 ms | 24.326 ms | 1.3745 ms | 1.00 | 0.00 | 218.7500 | 757.04 KB | + // 'Decode Jpeg - ImageSharp' | Core | Jpg/baseline/jpeg420exif.jpg | 44.93 ms | 3.088 ms | 0.1745 ms | 2.53 | 0.15 | 125.0000 | 529.96 KB | } } diff --git a/tests/ImageSharp.Benchmarks/General/Block8x8F_LoadFromInt16.cs b/tests/ImageSharp.Benchmarks/General/Block8x8F_LoadFromInt16.cs new file mode 100644 index 0000000000..34847148bf --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/Block8x8F_LoadFromInt16.cs @@ -0,0 +1,48 @@ +using System; +using System.Numerics; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Formats.Jpeg.Components; + +namespace SixLabors.ImageSharp.Benchmarks.General +{ + public class Block8x8F_LoadFromInt16 + { + private Block8x8 source; + + private Block8x8F dest = default; + + [GlobalSetup] + public void Setup() + { + if (Vector.Count != 8) + { + throw new NotSupportedException("Vector.Count != 8"); + } + + for (short i = 0; i < Block8x8F.Size; i++) + { + this.source[i] = i; + } + } + + [Benchmark(Baseline = true)] + public void Scalar() + { + this.dest.LoadFromInt16Scalar(ref this.source); + } + + [Benchmark] + public void ExtendedAvx2() + { + this.dest.LoadFromInt16ExtendedAvx2(ref this.source); + } + + // RESULT: + // Method | Mean | Error | StdDev | Scaled | + // ------------- |---------:|----------:|----------:|-------:| + // Scalar | 34.88 ns | 0.3296 ns | 0.3083 ns | 1.00 | + // ExtendedAvx2 | 21.58 ns | 0.2125 ns | 0.1884 ns | 0.62 | + } +} \ No newline at end of file From 941e51cd16a613023a270854763f7b3770a9424f Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 3 Nov 2018 17:52:55 +0100 Subject: [PATCH 277/381] reimplement Block8x8F.CopyTo2x2 --- .../Jpeg/Components/Block8x8F.CopyTo.cs | 166 +++++----- .../BlockOperations/Block8x8F_CopyTo2x2.cs | 287 ++++++++++++++++++ .../BlockOperations}/Block8x8F_DivideRound.cs | 6 +- .../Block8x8F_LoadFromInt16.cs | 9 +- .../Jpeg/BlockOperations}/Block8x8F_Round.cs | 7 +- .../Jpg/Block8x8FTests.CopyToBufferArea.cs | 21 +- 6 files changed, 390 insertions(+), 106 deletions(-) create mode 100644 tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs rename tests/ImageSharp.Benchmarks/{General => Codecs/Jpeg/BlockOperations}/Block8x8F_DivideRound.cs (96%) rename tests/ImageSharp.Benchmarks/{General => Codecs/Jpeg/BlockOperations}/Block8x8F_LoadFromInt16.cs (83%) rename tests/ImageSharp.Benchmarks/{General => Codecs/Jpeg/BlockOperations}/Block8x8F_Round.cs (90%) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs index b7dd125a88..50f8b61212 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs @@ -12,55 +12,32 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components internal partial struct Block8x8F { /// - /// Copy block data into the destination color buffer pixel area with the provided horizontal and vertical. + /// Copy block data into the destination color buffer pixel area with the provided horizontal and vertical scale factors. /// + [MethodImpl(InliningOptions.ShortMethod)] public void CopyTo(in BufferArea area, int horizontalScale, int verticalScale) { if (horizontalScale == 1 && verticalScale == 1) { - this.CopyTo(area); + this.Copy1x1Scale(area); return; } - else if (horizontalScale == 2 && verticalScale == 2) + + if (horizontalScale == 2 && verticalScale == 2) { - this.CopyTo2x2(area); + this.Copy2x2Scale(area); return; } - ref float destBase = ref area.GetReferenceToOrigin(); - - // TODO: Optimize: implement all the cases with loopless special code! (T4?) - for (int y = 0; y < 8; y++) - { - int yy = y * verticalScale; - int y8 = y * 8; - - for (int x = 0; x < 8; x++) - { - int xx = x * horizontalScale; - - float value = this[y8 + x]; - - for (int i = 0; i < verticalScale; i++) - { - int baseIdx = ((yy + i) * area.Stride) + xx; - - for (int j = 0; j < horizontalScale; j++) - { - // area[xx + j, yy + i] = value; - Unsafe.Add(ref destBase, baseIdx + j) = value; - } - } - } - } + // TODO: Optimize: implement all the cases with scale-specific, loopless code! + this.CopyArbitraryScale(area, horizontalScale, verticalScale); } - // [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyTo(in BufferArea area) + public void Copy1x1Scale(in BufferArea destination) { ref byte selfBase = ref Unsafe.As(ref this); - ref byte destBase = ref Unsafe.As(ref area.GetReferenceToOrigin()); - int destStride = area.Stride * sizeof(float); + ref byte destBase = ref Unsafe.As(ref destination.GetReferenceToOrigin()); + int destStride = destination.Stride * sizeof(float); CopyRowImpl(ref selfBase, ref destBase, destStride, 0); CopyRowImpl(ref selfBase, ref destBase, destStride, 1); @@ -80,10 +57,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components Unsafe.CopyBlock(ref d, ref s, 8 * sizeof(float)); } - private void CopyTo2x2(in BufferArea area) + private void Copy2x2Scale(in BufferArea area) { - ref float destBase = ref area.GetReferenceToOrigin(); - int destStride = area.Stride; + ref Vector2 destBase = ref Unsafe.As(ref area.GetReferenceToOrigin()); + int destStride = area.Stride / 2; this.WidenCopyImpl2x2(ref destBase, 0, destStride); this.WidenCopyImpl2x2(ref destBase, 1, destStride); @@ -96,60 +73,75 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void WidenCopyImpl2x2(ref float destBase, int row, int destStride) + private void WidenCopyImpl2x2(ref Vector2 destBase, int row, int destStride) { - ref Vector4 selfLeft = ref Unsafe.Add(ref this.V0L, 2 * row); - ref Vector4 selfRight = ref Unsafe.Add(ref selfLeft, 1); - ref float destLocalOrigo = ref Unsafe.Add(ref destBase, row * 2 * destStride); - - Unsafe.Add(ref destLocalOrigo, 0) = selfLeft.X; - Unsafe.Add(ref destLocalOrigo, 1) = selfLeft.X; - Unsafe.Add(ref destLocalOrigo, 2) = selfLeft.Y; - Unsafe.Add(ref destLocalOrigo, 3) = selfLeft.Y; - Unsafe.Add(ref destLocalOrigo, 4) = selfLeft.Z; - Unsafe.Add(ref destLocalOrigo, 5) = selfLeft.Z; - Unsafe.Add(ref destLocalOrigo, 6) = selfLeft.W; - Unsafe.Add(ref destLocalOrigo, 7) = selfLeft.W; - - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 0) = selfRight.X; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 1) = selfRight.X; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 2) = selfRight.Y; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 3) = selfRight.Y; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 4) = selfRight.Z; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 5) = selfRight.Z; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 6) = selfRight.W; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 7) = selfRight.W; - - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 0) = selfLeft.X; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 1) = selfLeft.X; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 2) = selfLeft.Y; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 3) = selfLeft.Y; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 4) = selfLeft.Z; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 5) = selfLeft.Z; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 6) = selfLeft.W; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 7) = selfLeft.W; - - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 0) = selfRight.X; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 1) = selfRight.X; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 2) = selfRight.Y; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 3) = selfRight.Y; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 4) = selfRight.Z; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 5) = selfRight.Z; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 6) = selfRight.W; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 7) = selfRight.W; + ref Vector4 sLeft = ref Unsafe.Add(ref this.V0L, 2 * row); + ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1); + + ref Vector2 dTopLeft = ref Unsafe.Add(ref destBase, 2 * row * destStride); + ref Vector2 dTopRight = ref Unsafe.Add(ref dTopLeft, 4); + ref Vector2 dBottomLeft = ref Unsafe.Add(ref dTopLeft, destStride); + ref Vector2 dBottomRight = ref Unsafe.Add(ref dBottomLeft, 4); + + var xLeft = new Vector4(sLeft.X); + var yLeft = new Vector4(sLeft.Y); + var zLeft = new Vector4(sLeft.Z); + var wLeft = new Vector4(sLeft.W); + + var xRight = new Vector4(sRight.X); + var yRight = new Vector4(sRight.Y); + var zRight = new Vector4(sRight.Z); + var wRight = new Vector4(sRight.W); + + Unsafe.As(ref dTopLeft) = xLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 1)) = yLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 2)) = zLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 3)) = wLeft; + + Unsafe.As(ref dTopRight) = xRight; + Unsafe.As(ref Unsafe.Add(ref dTopRight, 1)) = yRight; + Unsafe.As(ref Unsafe.Add(ref dTopRight, 2)) = zRight; + Unsafe.As(ref Unsafe.Add(ref dTopRight, 3)) = wRight; + + Unsafe.As(ref dBottomLeft) = xLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 1)) = yLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 2)) = zLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 3)) = wLeft; + + Unsafe.As(ref dBottomRight) = xRight; + Unsafe.As(ref Unsafe.Add(ref dBottomRight, 1)) = yRight; + Unsafe.As(ref Unsafe.Add(ref dBottomRight, 2)) = zRight; + Unsafe.As(ref Unsafe.Add(ref dBottomRight, 3)) = wRight; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void WidenCopyImpl(ref Vector4 s, ref float destBase) + [MethodImpl(InliningOptions.ColdPath)] + private void CopyArbitraryScale(BufferArea area, int horizontalScale, int verticalScale) { - Unsafe.Add(ref destBase, 0) = s.X; - Unsafe.Add(ref destBase, 1) = s.X; - Unsafe.Add(ref destBase, 2) = s.Y; - Unsafe.Add(ref destBase, 3) = s.Y; - Unsafe.Add(ref destBase, 4) = s.Z; - Unsafe.Add(ref destBase, 5) = s.Z; - Unsafe.Add(ref destBase, 6) = s.W; - Unsafe.Add(ref destBase, 7) = s.W; + ref float destBase = ref area.GetReferenceToOrigin(); + + for (int y = 0; y < 8; y++) + { + int yy = y * verticalScale; + int y8 = y * 8; + + for (int x = 0; x < 8; x++) + { + int xx = x * horizontalScale; + + float value = this[y8 + x]; + + for (int i = 0; i < verticalScale; i++) + { + int baseIdx = ((yy + i) * area.Stride) + xx; + + for (int j = 0; j < horizontalScale; j++) + { + // area[xx + j, yy + i] = value; + Unsafe.Add(ref destBase, baseIdx + j) = value; + } + } + } + } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs new file mode 100644 index 0000000000..89de95ee94 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs @@ -0,0 +1,287 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Formats.Jpeg.Components; +using SixLabors.ImageSharp.Memory; +// ReSharper disable InconsistentNaming + +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations +{ + public class Block8x8F_CopyTo2x2 + { + private Block8x8F block; + + private Buffer2D buffer; + + private BufferArea destArea; + + [GlobalSetup] + public void Setup() + { + this.buffer = Configuration.Default.MemoryAllocator.Allocate2D(1000, 500); + this.destArea = this.buffer.GetArea(200, 100, 128, 128); + } + + [Benchmark(Baseline = true)] + public void Original() + { + ref float destBase = ref this.destArea.GetReferenceToOrigin(); + int destStride = this.destArea.Stride; + + ref Block8x8F src = ref this.block; + + WidenCopyImpl2x2(ref src, ref destBase, 0, destStride); + WidenCopyImpl2x2(ref src, ref destBase, 1, destStride); + WidenCopyImpl2x2(ref src, ref destBase, 2, destStride); + WidenCopyImpl2x2(ref src, ref destBase, 3, destStride); + WidenCopyImpl2x2(ref src, ref destBase, 4, destStride); + WidenCopyImpl2x2(ref src, ref destBase, 5, destStride); + WidenCopyImpl2x2(ref src, ref destBase, 6, destStride); + WidenCopyImpl2x2(ref src, ref destBase, 7, destStride); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WidenCopyImpl2x2(ref Block8x8F src, ref float destBase, int row, int destStride) + { + ref Vector4 selfRight = ref Unsafe.Add(ref src.V0L, 2 * row); + ref Vector4 selfRight = ref Unsafe.Add(ref selfLeft, 1); + ref float destLocalOrigo = ref Unsafe.Add(ref destBase, row * 2 * destStride); + + Unsafe.Add(ref destLocalOrigo, 0) = selfLeft.X; + Unsafe.Add(ref destLocalOrigo, 1) = selfLeft.X; + Unsafe.Add(ref destLocalOrigo, 2) = selfLeft.Y; + Unsafe.Add(ref destLocalOrigo, 3) = selfLeft.Y; + Unsafe.Add(ref destLocalOrigo, 4) = selfLeft.Z; + Unsafe.Add(ref destLocalOrigo, 5) = selfLeft.Z; + Unsafe.Add(ref destLocalOrigo, 6) = selfLeft.W; + Unsafe.Add(ref destLocalOrigo, 7) = selfLeft.W; + + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 0) = selfRight.X; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 1) = selfRight.X; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 2) = selfRight.Y; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 3) = selfRight.Y; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 4) = selfRight.Z; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 5) = selfRight.Z; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 6) = selfRight.W; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 7) = selfRight.W; + + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 0) = selfLeft.X; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 1) = selfLeft.X; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 2) = selfLeft.Y; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 3) = selfLeft.Y; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 4) = selfLeft.Z; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 5) = selfLeft.Z; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 6) = selfLeft.W; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 7) = selfLeft.W; + + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 0) = selfRight.X; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 1) = selfRight.X; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 2) = selfRight.Y; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 3) = selfRight.Y; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 4) = selfRight.Z; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 5) = selfRight.Z; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 6) = selfRight.W; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 7) = selfRight.W; + } + + [Benchmark] + public void Original_V2() + { + ref float destBase = ref this.destArea.GetReferenceToOrigin(); + int destStride = this.destArea.Stride; + + ref Block8x8F src = ref this.block; + + WidenCopyImpl2x2_V2(ref src, ref destBase, 0, destStride); + WidenCopyImpl2x2_V2(ref src, ref destBase, 1, destStride); + WidenCopyImpl2x2_V2(ref src, ref destBase, 2, destStride); + WidenCopyImpl2x2_V2(ref src, ref destBase, 3, destStride); + WidenCopyImpl2x2_V2(ref src, ref destBase, 4, destStride); + WidenCopyImpl2x2_V2(ref src, ref destBase, 5, destStride); + WidenCopyImpl2x2_V2(ref src, ref destBase, 6, destStride); + WidenCopyImpl2x2_V2(ref src, ref destBase, 7, destStride); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WidenCopyImpl2x2_V2(ref Block8x8F src, ref float destBase, int row, int destStride) + { + ref Vector4 selfLeft = ref Unsafe.Add(ref src.V0L, 2 * row); + ref Vector4 selfRight = ref Unsafe.Add(ref selfLeft, 1); + ref float dest0 = ref Unsafe.Add(ref destBase, row * 2 * destStride); + + Unsafe.Add(ref dest0, 0) = selfLeft.X; + Unsafe.Add(ref dest0, 1) = selfLeft.X; + Unsafe.Add(ref dest0, 2) = selfLeft.Y; + Unsafe.Add(ref dest0, 3) = selfLeft.Y; + Unsafe.Add(ref dest0, 4) = selfLeft.Z; + Unsafe.Add(ref dest0, 5) = selfLeft.Z; + Unsafe.Add(ref dest0, 6) = selfLeft.W; + Unsafe.Add(ref dest0, 7) = selfLeft.W; + + ref float dest1 = ref Unsafe.Add(ref dest0, 8); + + Unsafe.Add(ref dest1, 0) = selfRight.X; + Unsafe.Add(ref dest1, 1) = selfRight.X; + Unsafe.Add(ref dest1, 2) = selfRight.Y; + Unsafe.Add(ref dest1, 3) = selfRight.Y; + Unsafe.Add(ref dest1, 4) = selfRight.Z; + Unsafe.Add(ref dest1, 5) = selfRight.Z; + Unsafe.Add(ref dest1, 6) = selfRight.W; + Unsafe.Add(ref dest1, 7) = selfRight.W; + + ref float dest2 = ref Unsafe.Add(ref dest0, destStride); + + Unsafe.Add(ref dest2, 0) = selfLeft.X; + Unsafe.Add(ref dest2, 1) = selfLeft.X; + Unsafe.Add(ref dest2, 2) = selfLeft.Y; + Unsafe.Add(ref dest2, 3) = selfLeft.Y; + Unsafe.Add(ref dest2, 4) = selfLeft.Z; + Unsafe.Add(ref dest2, 5) = selfLeft.Z; + Unsafe.Add(ref dest2, 6) = selfLeft.W; + Unsafe.Add(ref dest2, 7) = selfLeft.W; + + ref float dest3 = ref Unsafe.Add(ref dest2, 8); + + Unsafe.Add(ref dest3, 0) = selfRight.X; + Unsafe.Add(ref dest3, 1) = selfRight.X; + Unsafe.Add(ref dest3, 2) = selfRight.Y; + Unsafe.Add(ref dest3, 3) = selfRight.Y; + Unsafe.Add(ref dest3, 4) = selfRight.Z; + Unsafe.Add(ref dest3, 5) = selfRight.Z; + Unsafe.Add(ref dest3, 6) = selfRight.W; + Unsafe.Add(ref dest3, 7) = selfRight.W; + } + + [Benchmark] + public void UseVector2() + { + ref Vector2 destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin()); + int destStride = this.destArea.Stride / 2; + + ref Block8x8F src = ref this.block; + + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 0, destStride); + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 1, destStride); + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 2, destStride); + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 3, destStride); + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 4, destStride); + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 5, destStride); + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 6, destStride); + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 7, destStride); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WidenCopyImpl2x2_Vector2(ref Block8x8F src, ref Vector2 destBase, int row, int destStride) + { + ref Vector4 sLeft = ref Unsafe.Add(ref src.V0L, 2 * row); + ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1); + + ref Vector2 dTopLeft = ref Unsafe.Add(ref destBase, 2 * row * destStride); + ref Vector2 dTopRight = ref Unsafe.Add(ref dTopLeft, 4); + ref Vector2 dBottomLeft = ref Unsafe.Add(ref dTopLeft, destStride); + ref Vector2 dBottomRight = ref Unsafe.Add(ref dBottomLeft, 4); + + var xLeft = new Vector2(sLeft.X); + var yLeft = new Vector2(sLeft.Y); + var zLeft = new Vector2(sLeft.Z); + var wLeft = new Vector2(sLeft.W); + + var xRight = new Vector2(sRight.X); + var yRight = new Vector2(sRight.Y); + var zRight = new Vector2(sRight.Z); + var wRight = new Vector2(sRight.W); + + dTopLeft = xLeft; + Unsafe.Add(ref dTopLeft, 1) = yLeft; + Unsafe.Add(ref dTopLeft, 2) = zLeft; + Unsafe.Add(ref dTopLeft, 3) = wLeft; + + dTopRight = xRight; + Unsafe.Add(ref dTopRight, 1) = yRight; + Unsafe.Add(ref dTopRight, 2) = zRight; + Unsafe.Add(ref dTopRight, 3) = wRight; + + dBottomLeft = xLeft; + Unsafe.Add(ref dBottomLeft, 1) = yLeft; + Unsafe.Add(ref dBottomLeft, 2) = zLeft; + Unsafe.Add(ref dBottomLeft, 3) = wLeft; + + dBottomRight = xRight; + Unsafe.Add(ref dBottomRight, 1) = yRight; + Unsafe.Add(ref dBottomRight, 2) = zRight; + Unsafe.Add(ref dBottomRight, 3) = wRight; + } + + [Benchmark] + public void UseVector4() + { + ref Vector2 destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin()); + int destStride = this.destArea.Stride / 2; + + ref Block8x8F src = ref this.block; + + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 0, destStride); + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 1, destStride); + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 2, destStride); + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 3, destStride); + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 4, destStride); + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 5, destStride); + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 6, destStride); + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 7, destStride); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WidenCopyImpl2x2_Vector4(ref Block8x8F src, ref Vector2 destBase, int row, int destStride) + { + ref Vector4 sLeft = ref Unsafe.Add(ref src.V0L, 2 * row); + ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1); + + ref Vector2 dTopLeft = ref Unsafe.Add(ref destBase, 2 * row * destStride); + ref Vector2 dTopRight = ref Unsafe.Add(ref dTopLeft, 4); + ref Vector2 dBottomLeft = ref Unsafe.Add(ref dTopLeft, destStride); + ref Vector2 dBottomRight = ref Unsafe.Add(ref dBottomLeft, 4); + + var xLeft = new Vector4(sLeft.X); + var yLeft = new Vector4(sLeft.Y); + var zLeft = new Vector4(sLeft.Z); + var wLeft = new Vector4(sLeft.W); + + var xRight = new Vector4(sRight.X); + var yRight = new Vector4(sRight.Y); + var zRight = new Vector4(sRight.Z); + var wRight = new Vector4(sRight.W); + + Unsafe.As(ref dTopLeft) = xLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 1)) = yLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 2)) = zLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 3)) = wLeft; + + Unsafe.As(ref dTopRight) = xRight; + Unsafe.As(ref Unsafe.Add(ref dTopRight, 1)) = yRight; + Unsafe.As(ref Unsafe.Add(ref dTopRight, 2)) = zRight; + Unsafe.As(ref Unsafe.Add(ref dTopRight, 3)) = wRight; + + Unsafe.As(ref dBottomLeft) = xLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 1)) = yLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 2)) = zLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 3)) = wLeft; + + Unsafe.As(ref dBottomRight) = xRight; + Unsafe.As(ref Unsafe.Add(ref dBottomRight, 1)) = yRight; + Unsafe.As(ref Unsafe.Add(ref dBottomRight, 2)) = zRight; + Unsafe.As(ref Unsafe.Add(ref dBottomRight, 3)) = wRight; + } + + // RESULTS: + // Method | Mean | Error | StdDev | Scaled | + // ------------ |---------:|----------:|----------:|-------:| + // Original | 88.93 ns | 0.7783 ns | 0.6899 ns | 1.00 | + // Original_V2 | 88.39 ns | 0.9426 ns | 0.8356 ns | 0.99 | + // UseVector2 | 45.63 ns | 0.4248 ns | 0.3548 ns | 0.51 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Block8x8F_DivideRound.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_DivideRound.cs similarity index 96% rename from tests/ImageSharp.Benchmarks/General/Block8x8F_DivideRound.cs rename to tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_DivideRound.cs index fcc5f9a592..5502475d43 100644 --- a/tests/ImageSharp.Benchmarks/General/Block8x8F_DivideRound.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_DivideRound.cs @@ -10,7 +10,7 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components; // ReSharper disable InconsistentNaming -namespace SixLabors.ImageSharp.Benchmarks.General +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations { /// /// The goal of this benchmark is to measure the following Jpeg-related scenario: @@ -24,8 +24,8 @@ namespace SixLabors.ImageSharp.Benchmarks.General private static readonly Vector4 MinusOne = new Vector4(-1); private static readonly Vector4 Half = new Vector4(0.5f); - private Block8x8F inputDividend = default(Block8x8F); - private Block8x8F inputDivisior = default(Block8x8F); + private Block8x8F inputDividend; + private Block8x8F inputDivisior; [GlobalSetup] public void Setup() diff --git a/tests/ImageSharp.Benchmarks/General/Block8x8F_LoadFromInt16.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs similarity index 83% rename from tests/ImageSharp.Benchmarks/General/Block8x8F_LoadFromInt16.cs rename to tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs index 34847148bf..29ee402a00 100644 --- a/tests/ImageSharp.Benchmarks/General/Block8x8F_LoadFromInt16.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs @@ -1,11 +1,16 @@ -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// ReSharper disable InconsistentNaming + +using System; using System.Numerics; using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.Formats.Jpeg.Components; -namespace SixLabors.ImageSharp.Benchmarks.General +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations { public class Block8x8F_LoadFromInt16 { diff --git a/tests/ImageSharp.Benchmarks/General/Block8x8F_Round.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs similarity index 90% rename from tests/ImageSharp.Benchmarks/General/Block8x8F_Round.cs rename to tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs index 200af64c25..c7b5802c4f 100644 --- a/tests/ImageSharp.Benchmarks/General/Block8x8F_Round.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs @@ -1,4 +1,7 @@ -// ReSharper disable InconsistentNaming +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// ReSharper disable InconsistentNaming using System; using System.Numerics; @@ -8,7 +11,7 @@ using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.Formats.Jpeg.Components; -namespace SixLabors.ImageSharp.Benchmarks.General +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations { public class Block8x8F_Round { diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs index c720fdd4a7..3f426e232d 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs @@ -11,10 +11,11 @@ using SixLabors.Primitives; using Xunit; using Xunit.Abstractions; +// ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Formats.Jpg { - public partial class Block8x8FTests : JpegFixture + public partial class Block8x8FTests { public class CopyToBufferArea : JpegFixture { @@ -37,17 +38,15 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } } - // TODO: This test occasionally fails from the same reason certain ICC tests are failing. Should be false negative. - [Fact(Skip = "This test occasionally fails from the same reason certain ICC tests are failing. Should be false negative.")] - //[Fact] - public void Unscaled() + [Fact] + public void Copy1x1Scale() { Block8x8F block = CreateRandomFloatBlock(0, 100); - using (var buffer = Configuration.Default.MemoryAllocator.Allocate2D(20, 20)) + using (Buffer2D buffer = Configuration.Default.MemoryAllocator.Allocate2D(20, 20)) { BufferArea area = buffer.GetArea(5, 10, 8, 8); - block.CopyTo(area); + block.Copy1x1Scale(area); Assert.Equal(block[0, 0], buffer[5, 10]); Assert.Equal(block[1, 0], buffer[6, 10]); @@ -59,22 +58,20 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } } - // TODO: This test occasionally fails from the same reason certain ICC tests are failing. Should be false negative. - [Theory(Skip = "This test occasionally fails from the same reason certain ICC tests are failing. Should be false negative.")] - //[Theory] + [Theory] [InlineData(1, 1)] [InlineData(1, 2)] [InlineData(2, 1)] [InlineData(2, 2)] [InlineData(4, 2)] [InlineData(4, 4)] - public void Scaled(int horizontalFactor, int verticalFactor) + public void CopyTo(int horizontalFactor, int verticalFactor) { Block8x8F block = CreateRandomFloatBlock(0, 100); var start = new Point(50, 50); - using (var buffer = Configuration.Default.MemoryAllocator.Allocate2D(100, 100)) + using (Buffer2D buffer = Configuration.Default.MemoryAllocator.Allocate2D(100, 100)) { BufferArea area = buffer.GetArea(start.X, start.Y, 8 * horizontalFactor, 8 * verticalFactor); block.CopyTo(area, horizontalFactor, verticalFactor); From bc79b188176cb9db206006b21993a98b1fb99e2c Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 3 Nov 2018 18:31:43 +0100 Subject: [PATCH 278/381] Optimization: do not initialize pixel buffer in JpegDecoder --- .../Formats/Jpeg/JpegDecoderCore.cs | 10 ++++++-- src/ImageSharp/Image.Decode.cs | 24 ++++++++++++++++++ tests/ImageSharp.Tests/Image/ImageTests.cs | 25 ++++++++++++++++++- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 68252f624c..ef73aab38f 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -936,12 +936,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg private Image PostProcessIntoImage() where TPixel : struct, IPixel { + var image = Image.CreateUninitialized( + this.configuration, + this.ImageWidth, + this.ImageHeight, + this.MetaData); + using (var postProcessor = new JpegImagePostProcessor(this.configuration, this)) { - var image = new Image(this.configuration, this.ImageWidth, this.ImageHeight, this.MetaData); postProcessor.PostProcess(image.Frames.RootFrame); - return image; } + + return image; } } } \ No newline at end of file diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs index 8b9f3fdb5b..ffdab25e24 100644 --- a/src/ImageSharp/Image.Decode.cs +++ b/src/ImageSharp/Image.Decode.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; @@ -15,6 +16,29 @@ namespace SixLabors.ImageSharp /// public static partial class Image { + /// + /// Creates an instance backed by an uninitialized memory buffer. + /// This is an optimized creation method intended to be used by decoders. + /// The image might be filled with memory garbage. + /// + /// The pixel type + /// The + /// The width of the image + /// The height of the image + /// The + /// The result + internal static Image CreateUninitialized( + Configuration configuration, + int width, + int height, + ImageMetaData metadata) + where TPixel : struct, IPixel + { + Buffer2D uninitializedMemoryBuffer = + configuration.MemoryAllocator.Allocate2D(width, height); + return new Image(configuration, uninitializedMemoryBuffer.MemorySource, width, height, metadata); + } + /// /// By reading the header on the provided stream this calculates the images format. /// diff --git a/tests/ImageSharp.Tests/Image/ImageTests.cs b/tests/ImageSharp.Tests/Image/ImageTests.cs index f3c04d5e14..c5c7d19e1e 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.cs @@ -2,7 +2,10 @@ // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests.Memory; + using Xunit; // ReSharper disable InconsistentNaming @@ -46,7 +49,7 @@ namespace SixLabors.ImageSharp.Tests } [Fact] - public void Configuration_Width_Height_BackroundColor() + public void Configuration_Width_Height_BackgroundColor() { Configuration configuration = Configuration.Default.Clone(); Rgba32 color = Rgba32.Aquamarine; @@ -61,6 +64,26 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(configuration, image.GetConfiguration()); } } + + [Fact] + public void CreateUninitialized() + { + Configuration configuration = Configuration.Default.Clone(); + + byte dirtyValue = 123; + configuration.MemoryAllocator = new TestMemoryAllocator(dirtyValue); + var metadata = new ImageMetaData(); + + using (Image image = Image.CreateUninitialized(configuration, 21, 22, metadata)) + { + Assert.Equal(21, image.Width); + Assert.Equal(22, image.Height); + Assert.Same(configuration, image.GetConfiguration()); + Assert.Same(metadata, image.MetaData); + + Assert.Equal(dirtyValue, image[5, 5].PackedValue); + } + } } } } From c1e4ccb1728c4deb75d46d52af11c1faddbb3b80 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 3 Nov 2018 20:43:50 +0100 Subject: [PATCH 279/381] improved Block8x8F.Copy2x2Scale --- .../Jpeg/Components/Block8x8F.CopyTo.cs | 42 +++---- .../BlockOperations/Block8x8F_CopyTo1x1.cs | 82 ++++++++++++++ .../BlockOperations/Block8x8F_CopyTo2x2.cs | 104 ++++++++++++++---- 3 files changed, 190 insertions(+), 38 deletions(-) create mode 100644 tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs index 50f8b61212..5fa3e91d75 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components return; } - // TODO: Optimize: implement all the cases with scale-specific, loopless code! + // TODO: Optimize: implement all cases with scale-specific, loopless code! this.CopyArbitraryScale(area, horizontalScale, verticalScale); } @@ -79,9 +79,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1); ref Vector2 dTopLeft = ref Unsafe.Add(ref destBase, 2 * row * destStride); - ref Vector2 dTopRight = ref Unsafe.Add(ref dTopLeft, 4); ref Vector2 dBottomLeft = ref Unsafe.Add(ref dTopLeft, destStride); - ref Vector2 dBottomRight = ref Unsafe.Add(ref dBottomLeft, 4); var xLeft = new Vector4(sLeft.X); var yLeft = new Vector4(sLeft.Y); @@ -91,27 +89,33 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components var xRight = new Vector4(sRight.X); var yRight = new Vector4(sRight.Y); var zRight = new Vector4(sRight.Z); - var wRight = new Vector4(sRight.W); + var wRight = new Vector2(sRight.W); Unsafe.As(ref dTopLeft) = xLeft; - Unsafe.As(ref Unsafe.Add(ref dTopLeft, 1)) = yLeft; - Unsafe.As(ref Unsafe.Add(ref dTopLeft, 2)) = zLeft; - Unsafe.As(ref Unsafe.Add(ref dTopLeft, 3)) = wLeft; + AssignVector4Value(ref dTopLeft, 1, ref yLeft); + AssignVector4Value(ref dTopLeft, 2, ref zLeft); + AssignVector4Value(ref dTopLeft, 3, ref wLeft); - Unsafe.As(ref dTopRight) = xRight; - Unsafe.As(ref Unsafe.Add(ref dTopRight, 1)) = yRight; - Unsafe.As(ref Unsafe.Add(ref dTopRight, 2)) = zRight; - Unsafe.As(ref Unsafe.Add(ref dTopRight, 3)) = wRight; + AssignVector4Value(ref dTopLeft, 4, ref xRight); + AssignVector4Value(ref dTopLeft, 5, ref yRight); + AssignVector4Value(ref dTopLeft, 6, ref zRight); + Unsafe.Add(ref dTopLeft, 7) = wRight; Unsafe.As(ref dBottomLeft) = xLeft; - Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 1)) = yLeft; - Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 2)) = zLeft; - Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 3)) = wLeft; - - Unsafe.As(ref dBottomRight) = xRight; - Unsafe.As(ref Unsafe.Add(ref dBottomRight, 1)) = yRight; - Unsafe.As(ref Unsafe.Add(ref dBottomRight, 2)) = zRight; - Unsafe.As(ref Unsafe.Add(ref dBottomRight, 3)) = wRight; + AssignVector4Value(ref dBottomLeft, 1, ref yLeft); + AssignVector4Value(ref dBottomLeft, 2, ref zLeft); + AssignVector4Value(ref dBottomLeft, 3, ref wLeft); + + AssignVector4Value(ref dBottomLeft, 4, ref xRight); + AssignVector4Value(ref dBottomLeft, 5, ref yRight); + AssignVector4Value(ref dBottomLeft, 6, ref zRight); + Unsafe.Add(ref dBottomLeft, 7) = wRight; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void AssignVector4Value(ref Vector2 destBase, int offset, ref Vector4 value) + { + Unsafe.As(ref Unsafe.Add(ref destBase, offset)) = value; } [MethodImpl(InliningOptions.ColdPath)] diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs new file mode 100644 index 0000000000..96eecc456a --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs @@ -0,0 +1,82 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Formats.Jpeg.Components; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations +{ + public class Block8x8F_CopyTo1x1 + { + private Block8x8F block; + + private Buffer2D buffer; + + private BufferArea destArea; + + [GlobalSetup] + public void Setup() + { + if (!SimdUtils.IsAvx2CompatibleArchitecture) + { + throw new InvalidOperationException("Block8x8F_CopyTo1x1 is invalid on platforms without AVX2 support."); + } + + this.buffer = Configuration.Default.MemoryAllocator.Allocate2D(1000, 500); + this.destArea = this.buffer.GetArea(200, 100, 64, 64); + } + + [Benchmark(Baseline = true)] + public void Original() + { + ref byte selfBase = ref Unsafe.As(ref this.block); + ref byte destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin()); + int destStride = this.destArea.Stride * sizeof(float); + + CopyRowImpl(ref selfBase, ref destBase, destStride, 0); + CopyRowImpl(ref selfBase, ref destBase, destStride, 1); + CopyRowImpl(ref selfBase, ref destBase, destStride, 2); + CopyRowImpl(ref selfBase, ref destBase, destStride, 3); + CopyRowImpl(ref selfBase, ref destBase, destStride, 4); + CopyRowImpl(ref selfBase, ref destBase, destStride, 5); + CopyRowImpl(ref selfBase, ref destBase, destStride, 6); + CopyRowImpl(ref selfBase, ref destBase, destStride, 7); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void CopyRowImpl(ref byte selfBase, ref byte destBase, int destStride, int row) + { + ref byte s = ref Unsafe.Add(ref selfBase, row * 8 * sizeof(float)); + ref byte d = ref Unsafe.Add(ref destBase, row * destStride); + Unsafe.CopyBlock(ref d, ref s, 8 * sizeof(float)); + } + + [Benchmark] + public void UseVector8() + { + ref Block8x8F s = ref this.block; + ref Vector d = ref Unsafe.As>(ref this.destArea.GetReferenceToOrigin()); + + Vector row0 = Unsafe.As>(ref s.V0L); + Vector row1 = Unsafe.As>(ref s.V1L); + Vector row2 = Unsafe.As>(ref s.V2L); + Vector row3 = Unsafe.As>(ref s.V3L); + Vector row4 = Unsafe.As>(ref s.V4L); + Vector row5 = Unsafe.As>(ref s.V5L); + Vector row6 = Unsafe.As>(ref s.V6L); + Vector row7 = Unsafe.As>(ref s.V7L); + + d = row0; + Unsafe.Add(ref d, 1) = row1; + Unsafe.Add(ref d, 2) = row2; + Unsafe.Add(ref d, 3) = row3; + Unsafe.Add(ref d, 4) = row4; + Unsafe.Add(ref d, 5) = row5; + Unsafe.Add(ref d, 6) = row6; + Unsafe.Add(ref d, 7) = row7; + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs index 89de95ee94..269a3e0d81 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void WidenCopyImpl2x2(ref Block8x8F src, ref float destBase, int row, int destStride) { - ref Vector4 selfRight = ref Unsafe.Add(ref src.V0L, 2 * row); + ref Vector4 selfLeft = ref Unsafe.Add(ref src.V0L, 2 * row); ref Vector4 selfRight = ref Unsafe.Add(ref selfLeft, 1); ref float destLocalOrigo = ref Unsafe.Add(ref destBase, row * 2 * destStride); @@ -257,31 +257,97 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations var wRight = new Vector4(sRight.W); Unsafe.As(ref dTopLeft) = xLeft; - Unsafe.As(ref Unsafe.Add(ref dTopLeft, 1)) = yLeft; - Unsafe.As(ref Unsafe.Add(ref dTopLeft, 2)) = zLeft; - Unsafe.As(ref Unsafe.Add(ref dTopLeft, 3)) = wLeft; - + AssignVector4Value(ref dTopLeft, 1, ref yLeft); + AssignVector4Value(ref dTopLeft, 2, ref zLeft); + AssignVector4Value(ref dTopLeft, 3, ref wLeft); + Unsafe.As(ref dTopRight) = xRight; - Unsafe.As(ref Unsafe.Add(ref dTopRight, 1)) = yRight; - Unsafe.As(ref Unsafe.Add(ref dTopRight, 2)) = zRight; - Unsafe.As(ref Unsafe.Add(ref dTopRight, 3)) = wRight; + AssignVector4Value(ref dTopRight, 1, ref yRight); + AssignVector4Value(ref dTopRight, 2, ref zRight); + AssignVector4Value(ref dTopRight, 3, ref wRight); Unsafe.As(ref dBottomLeft) = xLeft; - Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 1)) = yLeft; - Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 2)) = zLeft; - Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 3)) = wLeft; + AssignVector4Value(ref dBottomLeft, 1, ref yLeft); + AssignVector4Value(ref dBottomLeft, 2, ref zLeft); + AssignVector4Value(ref dBottomLeft, 3, ref wLeft); Unsafe.As(ref dBottomRight) = xRight; - Unsafe.As(ref Unsafe.Add(ref dBottomRight, 1)) = yRight; - Unsafe.As(ref Unsafe.Add(ref dBottomRight, 2)) = zRight; - Unsafe.As(ref Unsafe.Add(ref dBottomRight, 3)) = wRight; + AssignVector4Value(ref dBottomRight, 1, ref yRight); + AssignVector4Value(ref dBottomRight, 2, ref zRight); + AssignVector4Value(ref dBottomRight, 3, ref wRight); + } + + [Benchmark] + public void UseVector4_SafeRightCorner() + { + ref Vector2 destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin()); + int destStride = this.destArea.Stride / 2; + + ref Block8x8F src = ref this.block; + + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 0, destStride); + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 1, destStride); + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 2, destStride); + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 3, destStride); + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 4, destStride); + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 5, destStride); + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 6, destStride); + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 7, destStride); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WidenCopyImpl2x2_Vector4_SafeRightCorner(ref Block8x8F src, ref Vector2 destBase, int row, int destStride) + { + ref Vector4 sLeft = ref Unsafe.Add(ref src.V0L, 2 * row); + ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1); + + ref Vector2 dTopLeft = ref Unsafe.Add(ref destBase, 2 * row * destStride); + ref Vector2 dBottomLeft = ref Unsafe.Add(ref dTopLeft, destStride); + + var xLeft = new Vector4(sLeft.X); + var yLeft = new Vector4(sLeft.Y); + var zLeft = new Vector4(sLeft.Z); + var wLeft = new Vector4(sLeft.W); + + var xRight = new Vector4(sRight.X); + var yRight = new Vector4(sRight.Y); + var zRight = new Vector4(sRight.Z); + var wRight = new Vector2(sRight.W); + + Unsafe.As(ref dTopLeft) = xLeft; + AssignVector4Value(ref dTopLeft, 1, ref yLeft); + AssignVector4Value(ref dTopLeft, 2, ref zLeft); + AssignVector4Value(ref dTopLeft, 3, ref wLeft); + + AssignVector4Value(ref dTopLeft, 4, ref xRight); + AssignVector4Value(ref dTopLeft, 5, ref yRight); + AssignVector4Value(ref dTopLeft, 6, ref zRight); + Unsafe.Add(ref dTopLeft, 7) = wRight; + + Unsafe.As(ref dBottomLeft) = xLeft; + AssignVector4Value(ref dBottomLeft, 1, ref yLeft); + AssignVector4Value(ref dBottomLeft, 2, ref zLeft); + AssignVector4Value(ref dBottomLeft, 3, ref wLeft); + + AssignVector4Value(ref dBottomLeft, 4, ref xRight); + AssignVector4Value(ref dBottomLeft, 5, ref yRight); + AssignVector4Value(ref dBottomLeft, 6, ref zRight); + Unsafe.Add(ref dBottomLeft, 7) = wRight; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void AssignVector4Value(ref Vector2 destBase, int offset, ref Vector4 value) + { + Unsafe.As(ref Unsafe.Add(ref destBase, offset)) = value; } // RESULTS: - // Method | Mean | Error | StdDev | Scaled | - // ------------ |---------:|----------:|----------:|-------:| - // Original | 88.93 ns | 0.7783 ns | 0.6899 ns | 1.00 | - // Original_V2 | 88.39 ns | 0.9426 ns | 0.8356 ns | 0.99 | - // UseVector2 | 45.63 ns | 0.4248 ns | 0.3548 ns | 0.51 | + // Method | Mean | Error | StdDev | Scaled | ScaledSD | + // --------------------------- |---------:|----------:|----------:|-------:|---------:| + // Original | 93.78 ns | 1.8419 ns | 1.9708 ns | 1.00 | 0.00 | + // Original_V2 | 89.85 ns | 0.8809 ns | 0.7356 ns | 0.96 | 0.02 | + // UseVector2 | 81.81 ns | 0.4441 ns | 0.3937 ns | 0.87 | 0.02 | + // UseVector4 | 55.74 ns | 0.3674 ns | 0.3068 ns | 0.59 | 0.01 | + // UseVector4_SafeRightCorner | 55.70 ns | 0.3239 ns | 0.2705 ns | 0.59 | 0.01 | } } \ No newline at end of file From c34e4ff85fa0f23cad7546182d02b8308e2f3bd4 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 3 Nov 2018 21:30:36 +0100 Subject: [PATCH 280/381] optimize ExifReader.ToEnum(...) --- .../MetaData/Profiles/Exif/ExifReader.cs | 21 +++++- .../BlockOperations/Block8x8F_CopyTo1x1.cs | 73 ++++++++++++++++--- .../Jpg/Block8x8FTests.CopyToBufferArea.cs | 3 +- .../Formats/Jpg/JpegProfilingBenchmarks.cs | 5 +- 4 files changed, 84 insertions(+), 18 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs index 3326c3217a..c6a5b7d232 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif private byte ConvertToByte(ReadOnlySpan buffer) => buffer[0]; - private unsafe string ConvertToString(ReadOnlySpan buffer) + private string ConvertToString(ReadOnlySpan buffer) { int nullCharIndex = buffer.IndexOf((byte)0); @@ -382,13 +382,13 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif this.invalidTags.Add(tag); } + [MethodImpl(InliningOptions.ShortMethod)] private TEnum ToEnum(int value, TEnum defaultValue) where TEnum : struct { - var enumValue = (TEnum)(object)value; - if (Enum.GetValues(typeof(TEnum)).Cast().Any(v => v.Equals(enumValue))) + if (EnumHelper.IsDefined(value)) { - return enumValue; + return Unsafe.As(ref value); } return defaultValue; @@ -557,5 +557,18 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif ? BinaryPrimitives.ReadInt16BigEndian(buffer) : BinaryPrimitives.ReadInt16LittleEndian(buffer); } + + private class EnumHelper + where TEnum : struct + { + private static readonly int[] Values = Enum.GetValues(typeof(TEnum)).Cast() + .Select(e => Convert.ToInt32(e)).OrderBy(e => e).ToArray(); + + [MethodImpl(InliningOptions.ShortMethod)] + public static bool IsDefined(int value) + { + return Array.BinarySearch(Values, 0, Values.Length, value) > 0; + } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs index 96eecc456a..bf9b1af338 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; using System.Numerics; using System.Runtime.CompilerServices; @@ -6,6 +9,7 @@ using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.Memory; +// ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations { @@ -22,7 +26,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations { if (!SimdUtils.IsAvx2CompatibleArchitecture) { - throw new InvalidOperationException("Block8x8F_CopyTo1x1 is invalid on platforms without AVX2 support."); + throw new InvalidOperationException("Benchmark Block8x8F_CopyTo1x1 is invalid on platforms without AVX2 support."); } this.buffer = Configuration.Default.MemoryAllocator.Allocate2D(1000, 500); @@ -58,7 +62,17 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations public void UseVector8() { ref Block8x8F s = ref this.block; - ref Vector d = ref Unsafe.As>(ref this.destArea.GetReferenceToOrigin()); + ref float origin = ref this.destArea.GetReferenceToOrigin(); + int stride = this.destArea.Stride; + + ref Vector d0 = ref Unsafe.As>(ref origin); + ref Vector d1 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride)); + ref Vector d2 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 2)); + ref Vector d3 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 3)); + ref Vector d4 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 4)); + ref Vector d5 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 5)); + ref Vector d6 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 6)); + ref Vector d7 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 7)); Vector row0 = Unsafe.As>(ref s.V0L); Vector row1 = Unsafe.As>(ref s.V1L); @@ -69,14 +83,51 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations Vector row6 = Unsafe.As>(ref s.V6L); Vector row7 = Unsafe.As>(ref s.V7L); - d = row0; - Unsafe.Add(ref d, 1) = row1; - Unsafe.Add(ref d, 2) = row2; - Unsafe.Add(ref d, 3) = row3; - Unsafe.Add(ref d, 4) = row4; - Unsafe.Add(ref d, 5) = row5; - Unsafe.Add(ref d, 6) = row6; - Unsafe.Add(ref d, 7) = row7; + d0 = row0; + d1 = row1; + d2 = row2; + d3 = row3; + d4 = row4; + d5 = row5; + d6 = row6; + d7 = row7; + } + + [Benchmark] + public void UseVector8_V2() + { + ref Block8x8F s = ref this.block; + ref float origin = ref this.destArea.GetReferenceToOrigin(); + int stride = this.destArea.Stride; + + ref Vector d0 = ref Unsafe.As>(ref origin); + ref Vector d1 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride)); + ref Vector d2 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 2)); + ref Vector d3 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 3)); + ref Vector d4 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 4)); + ref Vector d5 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 5)); + ref Vector d6 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 6)); + ref Vector d7 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 7)); + + d0 = Unsafe.As>(ref s.V0L); + d1 = Unsafe.As>(ref s.V1L); + d2 = Unsafe.As>(ref s.V2L); + d3 = Unsafe.As>(ref s.V3L); + d4 = Unsafe.As>(ref s.V4L); + d5 = Unsafe.As>(ref s.V5L); + d6 = Unsafe.As>(ref s.V6L); + d7 = Unsafe.As>(ref s.V7L); } + + // RESULTS: + // + // Method | Mean | Error | StdDev | Scaled | + // -------------- |---------:|----------:|----------:|-------:| + // Original | 22.53 ns | 0.1660 ns | 0.1553 ns | 1.00 | + // UseVector8 | 21.59 ns | 0.3079 ns | 0.2571 ns | 0.96 | + // UseVector8_V2 | 22.57 ns | 0.1699 ns | 0.1506 ns | 1.00 | + // + // Conclusion: + // Doesn't worth to bother with this } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs index 3f426e232d..d5eaaa2949 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs @@ -7,6 +7,7 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils; +using SixLabors.Memory; using SixLabors.Primitives; using Xunit; @@ -71,7 +72,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg var start = new Point(50, 50); - using (Buffer2D buffer = Configuration.Default.MemoryAllocator.Allocate2D(100, 100)) + using (Buffer2D buffer = Configuration.Default.MemoryAllocator.Allocate2D(100, 100, AllocationOptions.Clean)) { BufferArea area = buffer.GetArea(start.X, start.Y, 8 * horizontalFactor, 8 * verticalFactor); block.CopyTo(area, horizontalFactor, verticalFactor); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs index 7d5130e1bc..88959bfabd 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs @@ -32,8 +32,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Baseline.Jpeg444, }; - //[Theory] // Benchmark, enable manually - //[MemberData(nameof(DecodeJpegData))] + [Theory] // Benchmark, enable manually + [MemberData(nameof(DecodeJpegData))] public void DecodeJpeg(string fileName) { this.DecodeJpegBenchmarkImpl(fileName, new JpegDecoder()); @@ -62,6 +62,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg () => { var img = Image.Load(bytes, decoder); + img.Dispose(); }, // ReSharper disable once ExplicitCallerInfoArgument $"Decode {fileName}"); From b32694590da020985d443254a0305be21bb5f8a5 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 3 Nov 2018 22:05:06 +0100 Subject: [PATCH 281/381] Even better Copy2x2. Tests: Group together & refactor profiling benchmarks --- .../Jpeg/Components/Block8x8F.CopyTo.cs | 85 ++++++------- .../BlockOperations/Block8x8F_CopyTo2x2.cs | 115 +++++++++++++----- tests/ImageSharp.Sandbox46/Program.cs | 5 +- .../JpegBenchmarks.cs} | 23 ++-- .../LoadResizeSaveBenchmarks.cs} | 24 ++-- .../ProfilingBenchmarks/ProfilingSetup.cs | 18 +++ 6 files changed, 164 insertions(+), 106 deletions(-) rename tests/ImageSharp.Tests/{Formats/Jpg/JpegProfilingBenchmarks.cs => ProfilingBenchmarks/JpegBenchmarks.cs} (84%) rename tests/ImageSharp.Tests/{ProfilingBenchmarks.cs => ProfilingBenchmarks/LoadResizeSaveBenchmarks.cs} (67%) create mode 100644 tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs index 5fa3e91d75..6bf9c8483a 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs @@ -3,9 +3,9 @@ using System.Numerics; using System.Runtime.CompilerServices; - using SixLabors.ImageSharp.Memory; +// ReSharper disable UseObjectOrCollectionInitializer // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Formats.Jpeg.Components { @@ -62,60 +62,51 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components ref Vector2 destBase = ref Unsafe.As(ref area.GetReferenceToOrigin()); int destStride = area.Stride / 2; - this.WidenCopyImpl2x2(ref destBase, 0, destStride); - this.WidenCopyImpl2x2(ref destBase, 1, destStride); - this.WidenCopyImpl2x2(ref destBase, 2, destStride); - this.WidenCopyImpl2x2(ref destBase, 3, destStride); - this.WidenCopyImpl2x2(ref destBase, 4, destStride); - this.WidenCopyImpl2x2(ref destBase, 5, destStride); - this.WidenCopyImpl2x2(ref destBase, 6, destStride); - this.WidenCopyImpl2x2(ref destBase, 7, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 0, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 1, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 2, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 3, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 4, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 5, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 6, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 7, destStride); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void WidenCopyImpl2x2(ref Vector2 destBase, int row, int destStride) + private void WidenCopyRowImpl2x2(ref Vector2 destBase, int row, int destStride) { ref Vector4 sLeft = ref Unsafe.Add(ref this.V0L, 2 * row); ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1); - ref Vector2 dTopLeft = ref Unsafe.Add(ref destBase, 2 * row * destStride); - ref Vector2 dBottomLeft = ref Unsafe.Add(ref dTopLeft, destStride); - - var xLeft = new Vector4(sLeft.X); - var yLeft = new Vector4(sLeft.Y); - var zLeft = new Vector4(sLeft.Z); - var wLeft = new Vector4(sLeft.W); - - var xRight = new Vector4(sRight.X); - var yRight = new Vector4(sRight.Y); - var zRight = new Vector4(sRight.Z); - var wRight = new Vector2(sRight.W); - - Unsafe.As(ref dTopLeft) = xLeft; - AssignVector4Value(ref dTopLeft, 1, ref yLeft); - AssignVector4Value(ref dTopLeft, 2, ref zLeft); - AssignVector4Value(ref dTopLeft, 3, ref wLeft); - - AssignVector4Value(ref dTopLeft, 4, ref xRight); - AssignVector4Value(ref dTopLeft, 5, ref yRight); - AssignVector4Value(ref dTopLeft, 6, ref zRight); - Unsafe.Add(ref dTopLeft, 7) = wRight; - - Unsafe.As(ref dBottomLeft) = xLeft; - AssignVector4Value(ref dBottomLeft, 1, ref yLeft); - AssignVector4Value(ref dBottomLeft, 2, ref zLeft); - AssignVector4Value(ref dBottomLeft, 3, ref wLeft); - - AssignVector4Value(ref dBottomLeft, 4, ref xRight); - AssignVector4Value(ref dBottomLeft, 5, ref yRight); - AssignVector4Value(ref dBottomLeft, 6, ref zRight); - Unsafe.Add(ref dBottomLeft, 7) = wRight; - } + int offset = 2 * row * destStride; + ref Vector4 dTopLeft = ref Unsafe.As(ref Unsafe.Add(ref destBase, offset)); + ref Vector4 dBottomLeft = ref Unsafe.As(ref Unsafe.Add(ref destBase, offset + destStride)); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void AssignVector4Value(ref Vector2 destBase, int offset, ref Vector4 value) - { - Unsafe.As(ref Unsafe.Add(ref destBase, offset)) = value; + var xyLeft = new Vector4(sLeft.X); + xyLeft.Z = sLeft.Y; + xyLeft.W = sLeft.Y; + + var zwLeft = new Vector4(sLeft.Z); + zwLeft.Z = sLeft.W; + zwLeft.W = sLeft.W; + + var xyRight = new Vector4(sRight.X); + xyRight.Z = sRight.Y; + xyRight.W = sRight.Y; + + var zwRight = new Vector4(sRight.Z); + zwRight.Z = sRight.W; + zwRight.W = sRight.W; + + dTopLeft = xyLeft; + Unsafe.Add(ref dTopLeft, 1) = zwLeft; + Unsafe.Add(ref dTopLeft, 2) = xyRight; + Unsafe.Add(ref dTopLeft, 3) = zwRight; + + dBottomLeft = xyLeft; + Unsafe.Add(ref dBottomLeft, 1) = zwLeft; + Unsafe.Add(ref dBottomLeft, 2) = xyRight; + Unsafe.Add(ref dBottomLeft, 3) = zwRight; } [MethodImpl(InliningOptions.ColdPath)] diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs index 269a3e0d81..65176af5bb 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs @@ -257,24 +257,24 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations var wRight = new Vector4(sRight.W); Unsafe.As(ref dTopLeft) = xLeft; - AssignVector4Value(ref dTopLeft, 1, ref yLeft); - AssignVector4Value(ref dTopLeft, 2, ref zLeft); - AssignVector4Value(ref dTopLeft, 3, ref wLeft); - + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 1)) = yLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 2)) = zLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 3)) = wLeft; + Unsafe.As(ref dTopRight) = xRight; - AssignVector4Value(ref dTopRight, 1, ref yRight); - AssignVector4Value(ref dTopRight, 2, ref zRight); - AssignVector4Value(ref dTopRight, 3, ref wRight); + Unsafe.As(ref Unsafe.Add(ref dTopRight, 1)) = yRight; + Unsafe.As(ref Unsafe.Add(ref dTopRight, 2)) = zRight; + Unsafe.As(ref Unsafe.Add(ref dTopRight, 3)) = wRight; Unsafe.As(ref dBottomLeft) = xLeft; - AssignVector4Value(ref dBottomLeft, 1, ref yLeft); - AssignVector4Value(ref dBottomLeft, 2, ref zLeft); - AssignVector4Value(ref dBottomLeft, 3, ref wLeft); + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 1)) = yLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 2)) = zLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 3)) = wLeft; Unsafe.As(ref dBottomRight) = xRight; - AssignVector4Value(ref dBottomRight, 1, ref yRight); - AssignVector4Value(ref dBottomRight, 2, ref zRight); - AssignVector4Value(ref dBottomRight, 3, ref wRight); + Unsafe.As(ref Unsafe.Add(ref dBottomRight, 1)) = yRight; + Unsafe.As(ref Unsafe.Add(ref dBottomRight, 2)) = zRight; + Unsafe.As(ref Unsafe.Add(ref dBottomRight, 3)) = wRight; } [Benchmark] @@ -315,39 +315,90 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations var wRight = new Vector2(sRight.W); Unsafe.As(ref dTopLeft) = xLeft; - AssignVector4Value(ref dTopLeft, 1, ref yLeft); - AssignVector4Value(ref dTopLeft, 2, ref zLeft); - AssignVector4Value(ref dTopLeft, 3, ref wLeft); + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 1)) = yLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 2)) = zLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 3)) = wLeft; - AssignVector4Value(ref dTopLeft, 4, ref xRight); - AssignVector4Value(ref dTopLeft, 5, ref yRight); - AssignVector4Value(ref dTopLeft, 6, ref zRight); + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 4)) = xRight; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 5)) = yRight; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 6)) = zRight; Unsafe.Add(ref dTopLeft, 7) = wRight; Unsafe.As(ref dBottomLeft) = xLeft; - AssignVector4Value(ref dBottomLeft, 1, ref yLeft); - AssignVector4Value(ref dBottomLeft, 2, ref zLeft); - AssignVector4Value(ref dBottomLeft, 3, ref wLeft); + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 1)) = yLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 2)) = zLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 3)) = wLeft; - AssignVector4Value(ref dBottomLeft, 4, ref xRight); - AssignVector4Value(ref dBottomLeft, 5, ref yRight); - AssignVector4Value(ref dBottomLeft, 6, ref zRight); + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 4)) = xRight; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 5)) = yRight; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 6)) = zRight; Unsafe.Add(ref dBottomLeft, 7) = wRight; } + + [Benchmark] + public void UseVector4_V2() + { + ref Vector2 destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin()); + int destStride = this.destArea.Stride / 2; + + ref Block8x8F src = ref this.block; + + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 0, destStride); + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 1, destStride); + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 2, destStride); + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 3, destStride); + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 4, destStride); + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 5, destStride); + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 6, destStride); + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 7, destStride); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void AssignVector4Value(ref Vector2 destBase, int offset, ref Vector4 value) + private static void WidenCopyImpl2x2_Vector4_V2(ref Block8x8F src, ref Vector2 destBase, int row, int destStride) { - Unsafe.As(ref Unsafe.Add(ref destBase, offset)) = value; + ref Vector4 sLeft = ref Unsafe.Add(ref src.V0L, 2 * row); + ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1); + + int offset = 2 * row * destStride; + ref Vector4 dTopLeft = ref Unsafe.As(ref Unsafe.Add(ref destBase, offset)); + ref Vector4 dBottomLeft = ref Unsafe.As(ref Unsafe.Add(ref destBase, offset + destStride)); + + var xyLeft = new Vector4(sLeft.X); + xyLeft.Z = sLeft.Y; + xyLeft.W = sLeft.Y; + + var zwLeft = new Vector4(sLeft.Z); + zwLeft.Z = sLeft.W; + zwLeft.W = sLeft.W; + + var xyRight = new Vector4(sRight.X); + xyRight.Z = sRight.Y; + xyRight.W = sRight.Y; + + var zwRight = new Vector4(sRight.Z); + zwRight.Z = sRight.W; + zwRight.W = sRight.W; + + dTopLeft = xyLeft; + Unsafe.Add(ref dTopLeft, 1) = zwLeft; + Unsafe.Add(ref dTopLeft, 2) = xyRight; + Unsafe.Add(ref dTopLeft, 3) = zwRight; + + dBottomLeft = xyLeft; + Unsafe.Add(ref dBottomLeft, 1) = zwLeft; + Unsafe.Add(ref dBottomLeft, 2) = xyRight; + Unsafe.Add(ref dBottomLeft, 3) = zwRight; } // RESULTS: // Method | Mean | Error | StdDev | Scaled | ScaledSD | // --------------------------- |---------:|----------:|----------:|-------:|---------:| - // Original | 93.78 ns | 1.8419 ns | 1.9708 ns | 1.00 | 0.00 | - // Original_V2 | 89.85 ns | 0.8809 ns | 0.7356 ns | 0.96 | 0.02 | - // UseVector2 | 81.81 ns | 0.4441 ns | 0.3937 ns | 0.87 | 0.02 | - // UseVector4 | 55.74 ns | 0.3674 ns | 0.3068 ns | 0.59 | 0.01 | - // UseVector4_SafeRightCorner | 55.70 ns | 0.3239 ns | 0.2705 ns | 0.59 | 0.01 | + // Original | 92.69 ns | 2.4722 ns | 2.7479 ns | 1.00 | 0.00 | + // Original_V2 | 91.72 ns | 1.2089 ns | 1.0095 ns | 0.99 | 0.03 | + // UseVector2 | 86.70 ns | 0.5873 ns | 0.5206 ns | 0.94 | 0.03 | + // UseVector4 | 55.42 ns | 0.2482 ns | 0.2322 ns | 0.60 | 0.02 | + // UseVector4_SafeRightCorner | 58.97 ns | 0.4152 ns | 0.3884 ns | 0.64 | 0.02 | + // UseVector4_V2 | 41.88 ns | 0.3531 ns | 0.3303 ns | 0.45 | 0.01 | } } \ No newline at end of file diff --git a/tests/ImageSharp.Sandbox46/Program.cs b/tests/ImageSharp.Sandbox46/Program.cs index 3a3a7d31cd..c0bb25a1b9 100644 --- a/tests/ImageSharp.Sandbox46/Program.cs +++ b/tests/ImageSharp.Sandbox46/Program.cs @@ -4,6 +4,7 @@ // using SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations; +using SixLabors.ImageSharp.Tests.ProfilingBenchmarks; namespace SixLabors.ImageSharp.Sandbox46 { @@ -62,8 +63,8 @@ namespace SixLabors.ImageSharp.Sandbox46 private static void RunDecodeJpegProfilingTests() { Console.WriteLine("RunDecodeJpegProfilingTests..."); - var benchmarks = new JpegProfilingBenchmarks(new ConsoleOutput()); - foreach (object[] data in JpegProfilingBenchmarks.DecodeJpegData) + var benchmarks = new JpegBenchmarks(new ConsoleOutput()); + foreach (object[] data in JpegBenchmarks.DecodeJpegData) { string fileName = (string)data[0]; benchmarks.DecodeJpeg(fileName); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs similarity index 84% rename from tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs rename to tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs index 88959bfabd..3d439c5ce7 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs @@ -13,11 +13,11 @@ using SixLabors.ImageSharp.PixelFormats; using Xunit; using Xunit.Abstractions; -namespace SixLabors.ImageSharp.Tests.Formats.Jpg +namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks { - public class JpegProfilingBenchmarks : MeasureFixture + public class JpegBenchmarks : MeasureFixture { - public JpegProfilingBenchmarks(ITestOutputHelper output) + public JpegBenchmarks(ITestOutputHelper output) : base(output) { } @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Baseline.Jpeg444, }; - [Theory] // Benchmark, enable manually + [Theory(Skip = ProfilingSetup.SkipProfilingTests)] [MemberData(nameof(DecodeJpegData))] public void DecodeJpeg(string fileName) { @@ -69,11 +69,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } // Benchmark, enable manually! - // [Theory] - // [InlineData(1, 75, JpegSubsample.Ratio420)] - // [InlineData(30, 75, JpegSubsample.Ratio420)] - // [InlineData(30, 75, JpegSubsample.Ratio444)] - // [InlineData(30, 100, JpegSubsample.Ratio444)] + [Theory(Skip = ProfilingSetup.SkipProfilingTests)] + [InlineData(1, 75, JpegSubsample.Ratio420)] + [InlineData(30, 75, JpegSubsample.Ratio420)] + [InlineData(30, 75, JpegSubsample.Ratio444)] + [InlineData(30, 100, JpegSubsample.Ratio444)] public void EncodeJpeg(int executionCount, int quality, JpegSubsample subsample) { // do not run this on CI even by accident @@ -107,6 +107,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg $@"Encode {testFiles.Length} images" ); } + + foreach (Image image in testImages) + { + image.Dispose(); + } } } diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveBenchmarks.cs similarity index 67% rename from tests/ImageSharp.Tests/ProfilingBenchmarks.cs rename to tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveBenchmarks.cs index bc9b2a947b..3060722768 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveBenchmarks.cs @@ -1,31 +1,23 @@ -using System.IO; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.IO; -using SixLabors.ImageSharp.Formats.Jpeg; -using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; -using SixLabors.Primitives; using Xunit; using Xunit.Abstractions; -namespace SixLabors.ImageSharp.Tests +namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks { - public class ProfilingBenchmarks : MeasureFixture + public class LoadResizeSaveBenchmarks : MeasureFixture { - public const string SkipProfilingTests = -#if true - null; -#else - "Profiling benchmark, enable manually!"; -#endif - - - public ProfilingBenchmarks(ITestOutputHelper output) + public LoadResizeSaveBenchmarks(ITestOutputHelper output) : base(output) { } - [Theory(Skip = SkipProfilingTests)] + [Theory(Skip = ProfilingSetup.SkipProfilingTests)] [InlineData(TestImages.Jpeg.Baseline.Jpeg420Exif)] public void LoadResizeSave(string imagePath) { diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs new file mode 100644 index 0000000000..267c70219e --- /dev/null +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs @@ -0,0 +1,18 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// Uncomment to enable local profiling benchmarks. DO NOT PUSH TO MAIN! +#define PROFILING + +namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks +{ + public static class ProfilingSetup + { + public const string SkipProfilingTests = +#if PROFILING + null; +#else + "Profiling benchmark, enable manually!"; +#endif + } +} \ No newline at end of file From c791579f6e47b8bc68b67fee1910f6886867b8e0 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 3 Nov 2018 22:21:48 +0100 Subject: [PATCH 282/381] minor optimization in JpegColorConverter.FromGrayscale --- .../JpegColorConverter.FromGrayScale.cs | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) 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 5d7a31a12b..7424145c3b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs @@ -3,6 +3,8 @@ using System; using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { @@ -17,24 +19,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters 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; - - var v = new Vector4(0, 0, 0, 1); - var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F); + ref float sBase = ref MemoryMarshal.GetReference(values.Component0); + ref Vector4 dBase = ref MemoryMarshal.GetReference(result); + for (int i = 0; i < result.Length; i++) { - float y = yVals[i]; - - v.X = y; - v.Y = y; - v.Z = y; - + var v = new Vector4(Unsafe.Add(ref sBase, i)); + v.W = 1f; v *= scale; - - result[i] = v; + Unsafe.Add(ref dBase, i) = v; } } } From fa092d1511cbaf61c80d69c2257b5d457233ef8e Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 00:19:29 +0100 Subject: [PATCH 283/381] add JpegSnoop reports for all current input Jpeg --- .../JpegSnoopReports/Calliphora.jpg.txt | 331 ++++++++ .../JpegSnoopReports/Floorplan.jpg.txt | 266 ++++++ .../JpegSnoopReports/Hiyamugi.jpg.txt | 319 ++++++++ .../baseline/JpegSnoopReports/Lake.jpg.txt | 683 ++++++++++++++++ .../MultiScanBaselineCMYK.jpg.txt | 282 +++++++ .../baseline/JpegSnoopReports/Snake.jpg.txt | 683 ++++++++++++++++ .../baseline/JpegSnoopReports/badeof.jpg.txt | 347 ++++++++ .../baseline/JpegSnoopReports/badrst.jpg.txt | 434 ++++++++++ .../baseline/JpegSnoopReports/cmyk.jpg.txt | 435 ++++++++++ .../baseline/JpegSnoopReports/exif.jpg.txt | 454 ++++++++++ .../gamma_dalai_lama_gray.jpg.txt | 339 ++++++++ .../JpegSnoopReports/jpeg400jfif.jpg.txt | 211 +++++ .../JpegSnoopReports/jpeg420exif.jpg.txt | 412 ++++++++++ .../JpegSnoopReports/jpeg420small.jpg.txt | 330 ++++++++ .../baseline/JpegSnoopReports/jpeg444.jpg.txt | 405 +++++++++ .../JpegSnoopReports/ratio-1x1.jpg.txt | 338 ++++++++ .../JpegSnoopReports/testimgint.jpg.txt | 342 ++++++++ .../JpegSnoopReports/testorig.jpg.txt | 342 ++++++++ .../baseline/JpegSnoopReports/turtle.jpg.txt | 367 +++++++++ .../baseline/JpegSnoopReports/ycck.jpg.txt | 640 +++++++++++++++ ...59-MissingFF00-Progressive-Bedroom.jpg.txt | 461 +++++++++++ ...ue159-MissingFF00-Progressive-Girl.jpg.txt | 520 ++++++++++++ ...ssue178-BadCoeffsProgressive-Lemon.jpg.txt | 471 +++++++++++ .../Issue214-CriticalEOF .jpg.txt | 94 +++ .../Issue385-BadZigZag-Progressive.jpg.txt | 468 +++++++++++ ...e394-MultiHuffmanBaseline-Speakers.jpg.txt | 438 ++++++++++ .../Issue517-No-EOI-Progressive.jpg.txt | 406 +++++++++ .../Issue518-Bad-RST-Progressive.jpg.txt | 759 +++++++++++++++++ .../Issue520-InvalidCast.jpg.txt | 364 +++++++++ ...24-DhtHasWrongLength-Progressive-N.jpg.txt | 284 +++++++ .../Issue694-Decode-Exif-OutOfRange.jpg.txt | 368 +++++++++ .../Issue695-Invalid-EOI.jpg.txt | 39 + .../Issue696-Resize-Exif-OutOfRange.jpg.txt | 377 +++++++++ .../Issue721-InvalidAPP0.jpg.txt | 446 ++++++++++ ...-Ordered-Interleaved-Progressive-A.jpg.txt | 519 ++++++++++++ ...-Ordered-Interleaved-Progressive-B.jpg.txt | 477 +++++++++++ ...-Ordered-Interleaved-Progressive-C.jpg.txt | 484 +++++++++++ .../issue750-exif-load.jpg.txt | 772 ++++++++++++++++++ .../issue750-exif-tranform.jpg.txt | 435 ++++++++++ .../BadEofProgressive.jpg.txt | 452 ++++++++++ .../JpegSnoopReports/ExifUndefType.jpg.txt | 535 ++++++++++++ .../JpegSnoopReports/Festzug.jpg.txt | 459 +++++++++++ .../progressive/JpegSnoopReports/fb.jpg.txt | 525 ++++++++++++ .../JpegSnoopReports/progress.jpg.txt | 468 +++++++++++ 44 files changed, 18581 insertions(+) create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/Calliphora.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/Floorplan.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/Hiyamugi.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/Lake.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/MultiScanBaselineCMYK.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/Snake.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/badeof.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/badrst.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/cmyk.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/exif.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/gamma_dalai_lama_gray.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg400jfif.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg420exif.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg420small.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg444.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/ratio-1x1.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/testimgint.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/testorig.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/turtle.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/ycck.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue159-MissingFF00-Progressive-Bedroom.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue159-MissingFF00-Progressive-Girl.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue178-BadCoeffsProgressive-Lemon.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue214-CriticalEOF .jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue385-BadZigZag-Progressive.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue394-MultiHuffmanBaseline-Speakers.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue517-No-EOI-Progressive.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue518-Bad-RST-Progressive.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue520-InvalidCast.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue624-DhtHasWrongLength-Progressive-N.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue694-Decode-Exif-OutOfRange.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue695-Invalid-EOI.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue696-Resize-Exif-OutOfRange.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue721-InvalidAPP0.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-A.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-B.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-C.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/issue750-exif-load.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/issue750-exif-tranform.jpg.txt create mode 100644 tests/Images/Input/Jpg/progressive/JpegSnoopReports/BadEofProgressive.jpg.txt create mode 100644 tests/Images/Input/Jpg/progressive/JpegSnoopReports/ExifUndefType.jpg.txt create mode 100644 tests/Images/Input/Jpg/progressive/JpegSnoopReports/Festzug.jpg.txt create mode 100644 tests/Images/Input/Jpg/progressive/JpegSnoopReports/fb.jpg.txt create mode 100644 tests/Images/Input/Jpg/progressive/JpegSnoopReports/progress.jpg.txt diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Calliphora.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Calliphora.jpg.txt new file mode 100644 index 0000000000..dc889ab105 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Calliphora.jpg.txt @@ -0,0 +1,331 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Calliphora.jpg] + Filesize: [254766] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 96 x 96 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: COM (Comment) (xFFFE) *** + OFFSET: 0x00000014 + Comment length = 80 + Comment=File source: http://commons.wikimedia.org/wiki/File:Calliphora_sp_Portrait.jpg + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000066 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 10 16 20 24 + DQT, Row #1: 5 5 6 8 10 23 24 22 + DQT, Row #2: 6 5 6 10 16 23 28 22 + DQT, Row #3: 6 7 9 12 20 35 32 25 + DQT, Row #4: 7 9 15 22 27 44 41 31 + DQT, Row #5: 10 14 22 26 32 42 45 37 + DQT, Row #6: 20 26 31 35 41 48 48 40 + DQT, Row #7: 29 37 38 39 45 40 41 40 + Approx quality factor = 79.94 (scaling=40.12 variance=1.43) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000000AB + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 7 7 10 19 40 40 40 40 + DQT, Row #1: 7 8 10 26 40 40 40 40 + DQT, Row #2: 10 10 22 40 40 40 40 40 + DQT, Row #3: 19 26 40 40 40 40 40 40 + DQT, Row #4: 40 40 40 40 40 40 40 40 + DQT, Row #5: 40 40 40 40 40 40 40 40 + DQT, Row #6: 40 40 40 40 40 40 40 40 + DQT, Row #7: 40 40 40 40 40 40 40 40 + Approx quality factor = 79.87 (scaling=40.26 variance=0.36) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x000000F0 + Frame header length = 17 + Precision = 8 + Number of Lines = 1198 + Samples per Line = 804 + Image Size = 804 x 1198 + Raw Image Orientation = Portrait + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000103 + Huffman table length = 28 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 04 + Codes of length 03 bits (005 total): 00 01 02 03 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000121 + Huffman table length = 79 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 06 31 + Codes of length 07 bits (004 total): 13 22 41 51 + Codes of length 08 bits (004 total): 14 32 61 71 + Codes of length 09 bits (003 total): 07 81 91 + Codes of length 10 bits (006 total): 15 23 42 52 A1 B1 + Codes of length 11 bits (003 total): 33 62 C1 + Codes of length 12 bits (007 total): 16 24 43 72 82 D1 F0 + Codes of length 13 bits (002 total): 25 E1 + Codes of length 14 bits (003 total): 34 53 92 + Codes of length 15 bits (002 total): A2 F1 + Codes of length 16 bits (015 total): 08 63 B2 26 44 C2 D2 73 27 35 55 74 84 93 A3 + Total number of codes: 060 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000172 + Huffman table length = 26 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 007 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000018E + Huffman table length = 59 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (002 total): 03 31 + Codes of length 06 bits (004 total): 12 41 51 F0 + Codes of length 07 bits (003 total): 04 61 71 + Codes of length 08 bits (008 total): 13 22 81 91 A1 B1 C1 D1 + Codes of length 09 bits (002 total): 32 E1 + Codes of length 10 bits (002 total): 42 F1 + Codes of length 11 bits (002 total): 05 23 + Codes of length 12 bits (002 total): 52 62 + Codes of length 13 bits (002 total): 14 33 + Codes of length 14 bits (001 total): 72 + Codes of length 15 bits (004 total): 24 82 92 A2 + Codes of length 16 bits (003 total): 43 B2 E2 + Total number of codes: 040 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000001CB + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000001D9 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0003E32C.0 + + Compression stats: + Compression Ratio: 11.36:1 + Bits per pixel: 2.11:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2628 ( 17%) + # codes of length 03 bits: 10491 ( 69%) + # codes of length 04 bits: 1319 ( 9%) + # codes of length 05 bits: 611 ( 4%) + # codes of length 06 bits: 101 ( 1%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 23843 ( 79%) + # codes of length 03 bits: 3770 ( 12%) + # codes of length 04 bits: 1945 ( 6%) + # codes of length 05 bits: 653 ( 2%) + # codes of length 06 bits: 89 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 118632 ( 45%) + # codes of length 03 bits: 34447 ( 13%) + # codes of length 04 bits: 57131 ( 22%) + # codes of length 05 bits: 27139 ( 10%) + # codes of length 06 bits: 8648 ( 3%) + # codes of length 07 bits: 9574 ( 4%) + # codes of length 08 bits: 4195 ( 2%) + # codes of length 09 bits: 1503 ( 1%) + # codes of length 10 bits: 1711 ( 1%) + # codes of length 11 bits: 386 ( 0%) + # codes of length 12 bits: 470 ( 0%) + # codes of length 13 bits: 66 ( 0%) + # codes of length 14 bits: 62 ( 0%) + # codes of length 15 bits: 38 ( 0%) + # codes of length 16 bits: 58 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 58553 ( 58%) + # codes of length 03 bits: 21076 ( 21%) + # codes of length 04 bits: 4270 ( 4%) + # codes of length 05 bits: 6075 ( 6%) + # codes of length 06 bits: 6016 ( 6%) + # codes of length 07 bits: 2009 ( 2%) + # codes of length 08 bits: 2750 ( 3%) + # codes of length 09 bits: 429 ( 0%) + # codes of length 10 bits: 213 ( 0%) + # codes of length 11 bits: 91 ( 0%) + # codes of length 12 bits: 44 ( 0%) + # codes of length 13 bits: 22 ( 0%) + # codes of length 14 bits: 5 ( 0%) + # codes of length 15 bits: 9 ( 0%) + # codes of length 16 bits: 3 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[119] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1008, 0, 0] RGB=[254,254,254] @ MCU[ 35, 37] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x0003E32C.0 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0003E32C + + +*** Searching Compression Signatures *** + + Signature: 01DC499064BA9264D591FDE9071DFD89 + Signature (Rotated): 0175BAF3251040E0EFB2930B73328E7F + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C40Z,D40Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C700UZ ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + SW :[Apple ImageIO.framework ] [050 (Normal) ] + SW :[IJG Library ] [080 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [080 ] + SW :[IrfanView ] [080 ] + SW :[idImager ] [080 ] + SW :[FastStone Image Viewer ] [080 ] + SW :[NeatImage ] [080 ] + SW :[Paint.NET ] [080 ] + SW :[Photomatix ] [080 ] + SW :[XnView ] [080 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Floorplan.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Floorplan.jpg.txt new file mode 100644 index 0000000000..2c03157afe --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Floorplan.jpg.txt @@ -0,0 +1,266 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Floorplan.jpg] + Filesize: [161577] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 300 x 300 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 13464 + Identifier = [Exif] + Identifier TIFF = 0x[4D4D002A 00000008] + Endian = Motorola (big) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x000A + [Model ] = "Photosmart Plus B209a-m" + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 300/1 + [YResolution ] = 300/1 + [ResolutionUnit ] = Inch + [Software ] = "Windows Photo Editor 10.0.10011.16384" + [DateTime ] = "2016:01:02 20:17:37" + [ExifOffset ] = @ 0x091A + Offset to Next IFD = 0x000011B6 + + EXIF IFD1 @ Absolute 0x000011D4 + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 96/1 + [YResolution ] = 96/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x1214 = @ 0x1232 + [JpegIFByteCount ] = 0x[0000227C] / 8828 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x00000938 + Dir Length = 0x0008 + [DateTimeOriginal ] = "2016:01:02 19:22:28" + [DateTimeDigitized ] = "2016:01:02 19:22:28" + [SubSecTimeOriginal ] = "00" + [SubSecTimeDigitized ] = "00" + [ColorSpace ] = sRGB + [ExifImageWidth ] = 0x[00000922] / 2338 + [ExifImageHeight ] = 0x[000008C9] / 2249 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x000034AE + Length = 12772 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + | + |Windows Photo Editor 10.0.10011.163842016-01-02T19:22:28 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00006694 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 5 8 10 12 + DQT, Row #1: 2 2 3 4 5 12 12 11 + DQT, Row #2: 3 3 3 5 8 11 14 11 + DQT, Row #3: 3 3 4 6 10 17 16 12 + DQT, Row #4: 4 4 7 11 14 22 21 15 + DQT, Row #5: 5 7 11 13 16 21 23 18 + DQT, Row #6: 10 13 16 17 21 24 24 20 + DQT, Row #7: 14 18 19 20 22 20 21 20 + Approx quality factor = 90.06 (scaling=19.88 variance=1.14) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x000066D9 + Frame header length = 11 + Precision = 8 + Number of Lines = 645 + Samples per Line = 976 + Image Size = 976 x 645 + Raw Image Orientation = Landscape + Number of Img components = 1 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000066E6 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00006707 + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000067BE + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000067C8 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00027727.0 + + Compression stats: + Compression Ratio: 4.66:1 + Bits per pixel: 1.72:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 3571 ( 36%) + # codes of length 03 bits: 4320 ( 44%) + # codes of length 04 bits: 925 ( 9%) + # codes of length 05 bits: 456 ( 5%) + # codes of length 06 bits: 313 ( 3%) + # codes of length 07 bits: 291 ( 3%) + # codes of length 08 bits: 6 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 78118 ( 44%) + # codes of length 03 bits: 22349 ( 13%) + # codes of length 04 bits: 35264 ( 20%) + # codes of length 05 bits: 18811 ( 11%) + # codes of length 06 bits: 4312 ( 2%) + # codes of length 07 bits: 8245 ( 5%) + # codes of length 08 bits: 4682 ( 3%) + # codes of length 09 bits: 1584 ( 1%) + # codes of length 10 bits: 1900 ( 1%) + # codes of length 11 bits: 324 ( 0%) + # codes of length 12 bits: 116 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 6 ( 0%) + # codes of length 16 bits: 639 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[231] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1017, 0, 0] RGB=[255,255,255] @ MCU[ 7, 0] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00027726.4 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00027727 + + +*** Searching Compression Signatures *** + + Signature: 015C645021E37D3469A6B652789383DB + Signature (Rotated): 01D400C125EB43B05762A66347B271F7 + File Offset: 0 bytes + Chroma subsampling: Gray + EXIF Make/Model: OK [???] [Photosmart Plus B209a-m] + EXIF Makernotes: NONE + EXIF Software: OK [Windows Photo Editor 10.0.10011.16384] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[IJG Library ] [090 Gray ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [090 Gray ] + SW :[IrfanView ] [090 Gray ] + SW :[idImager ] [090 Gray ] + SW :[FastStone Image Viewer ] [090 Gray ] + SW :[NeatImage ] [090 Gray ] + SW :[Paint.NET ] [090 Gray ] + SW :[Photomatix ] [090 Gray ] + SW :[XnView ] [090 Gray ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 2 - Image has high probability of being processed/edited + + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Hiyamugi.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Hiyamugi.jpg.txt new file mode 100644 index 0000000000..8538e13c86 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Hiyamugi.jpg.txt @@ -0,0 +1,319 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Hiyamugi.jpg] + Filesize: [540458] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.0] + density = 96 x 96 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000014 + Length = 65110 + Identifier = [JFXX] + Not known APP0 type. Skipping remainder. + +*** Marker: COM (Comment) (xFFFE) *** + OFFSET: 0x0000FE6C + Comment length = 31 + Comment=LEAD Technologies Inc. V1.01. + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0000FE8D + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 2 2 2 2 2 2 2 2 + DQT, Row #1: 2 2 2 2 2 2 2 2 + DQT, Row #2: 2 2 2 2 2 2 2 2 + DQT, Row #3: 2 2 2 2 2 3 3 2 + DQT, Row #4: 2 2 2 2 2 4 4 3 + DQT, Row #5: 2 2 2 2 3 4 4 3 + DQT, Row #6: 2 2 3 3 4 4 4 4 + DQT, Row #7: 2 3 3 3 4 4 4 3 + Approx quality factor = 96.75 (scaling=6.50 variance=21.01) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 2 2 2 2 3 3 3 3 + DQT, Row #1: 2 2 2 2 3 3 3 3 + DQT, Row #2: 2 2 2 3 3 3 3 3 + DQT, Row #3: 2 2 3 3 3 3 3 3 + DQT, Row #4: 3 3 3 3 3 3 3 3 + DQT, Row #5: 3 3 3 3 3 3 3 3 + DQT, Row #6: 3 3 3 3 3 3 3 3 + DQT, Row #7: 3 3 3 3 3 3 3 3 + Approx quality factor = 98.06 (scaling=3.88 variance=4.78) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000FF13 + Huffman table length = 418 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x000100B7 + Frame header length = 17 + Precision = 8 + Number of Lines = 794 + Samples per Line = 1123 + Image Size = 1123 x 794 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000100CA + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000100D8 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00083F28.0 + + Compression stats: + Compression Ratio: 5.64:1 + Bits per pixel: 4.26:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 727 ( 5%) + # codes of length 03 bits: 7443 ( 52%) + # codes of length 04 bits: 2171 ( 15%) + # codes of length 05 bits: 1627 ( 11%) + # codes of length 06 bits: 1355 ( 10%) + # codes of length 07 bits: 785 ( 6%) + # codes of length 08 bits: 92 ( 1%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2590 ( 36%) + # codes of length 03 bits: 1357 ( 19%) + # codes of length 04 bits: 1187 ( 17%) + # codes of length 05 bits: 856 ( 12%) + # codes of length 06 bits: 616 ( 9%) + # codes of length 07 bits: 346 ( 5%) + # codes of length 08 bits: 109 ( 2%) + # codes of length 09 bits: 39 ( 1%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 223973 ( 44%) + # codes of length 03 bits: 69375 ( 14%) + # codes of length 04 bits: 93550 ( 19%) + # codes of length 05 bits: 58421 ( 12%) + # codes of length 06 bits: 13137 ( 3%) + # codes of length 07 bits: 22630 ( 4%) + # codes of length 08 bits: 9176 ( 2%) + # codes of length 09 bits: 6545 ( 1%) + # codes of length 10 bits: 3947 ( 1%) + # codes of length 11 bits: 1890 ( 0%) + # codes of length 12 bits: 1162 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 77 ( 0%) + # codes of length 16 bits: 1763 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 44319 ( 35%) + # codes of length 03 bits: 21048 ( 17%) + # codes of length 04 bits: 24019 ( 19%) + # codes of length 05 bits: 17303 ( 14%) + # codes of length 06 bits: 9470 ( 7%) + # codes of length 07 bits: 2699 ( 2%) + # codes of length 08 bits: 3432 ( 3%) + # codes of length 09 bits: 2092 ( 2%) + # codes of length 10 bits: 717 ( 1%) + # codes of length 11 bits: 679 ( 1%) + # codes of length 12 bits: 85 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 150 ( 0%) + # codes of length 15 bits: 75 ( 0%) + # codes of length 16 bits: 425 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[117] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 812, 102, -218] RGB=[189,244,250] @ MCU[ 19, 16] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00083F27.7 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00083F28 + + +*** Searching Compression Signatures *** + + Signature: 0193B6220463E5A621ED25A53EC2FE7D + Signature (Rotated): 010D9693F4FC34B402EFA979BED34733 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[LEAD Technologies Inc ] [002 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Lake.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Lake.jpg.txt new file mode 100644 index 0000000000..900f52cb78 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Lake.jpg.txt @@ -0,0 +1,683 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Lake.jpg] + Filesize: [206342] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000002 + Length = 10392 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000014 + Dir Length = 0x0008 + [Make ] = "Canon" + [Model ] = "Canon EOS DIGITAL REBEL XSi" + [XResolution ] = 300/1 + [YResolution ] = 300/1 + [ResolutionUnit ] = Inch + [Software ] = "Adobe Photoshop Camera Raw 9.8 (Windows)" + [DateTime ] = "2016:12:29 12:57:54" + [ExifOffset ] = @ 0x00DE + Offset to Next IFD = 0x000002D6 + + EXIF IFD1 @ Absolute 0x000002E2 + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x0334 = @ 0x0340 + [JpegIFByteCount ] = 0x[0000255C] / 9564 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000EA + Dir Length = 0x001B + [ExposureTime ] = 1/640 s + [FNumber ] = F8.0 + [ExposureProgram ] = Normal program + [ISOSpeedRatings ] = 200 + [ExifVersion ] = 02.30 + [DateTimeOriginal ] = "2009:07:19 17:00:36" + [DateTimeDigitized ] = "2009:07:19 17:00:36" + [ShutterSpeedValue ] = 9321928/1000000 + [ApertureValue ] = 6/1 + [ExposureBiasValue ] = 0.00 eV + [MaxApertureValue ] = 4/1 + [MeteringMode ] = Pattern + [Flash ] = Flash did not fire + [FocalLength ] = 200 mm + [SubSecTimeOriginal ] = "73" + [SubSecTimeDigitized ] = "73" + [ColorSpace ] = Uncalibrated + [FocalPlaneXResolution ] = 4272000/878 + [FocalPlaneYResolution ] = 2848000/584 + [FocalPlaneResolutionUnit ] = Inch + [CustomRendered ] = Normal process + [ExposureMode ] = Auto exposure + [WhiteBalance ] = Auto white balance + [SceneCaptureType ] = Standard + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x0000289C + Length = 9752 + Identifier = [Photoshop 3.0] + 8BIM: [0x03ED] Name="" Len=[0x0010] DefinedName="ResolutionInfo structure" + Horizontal resolution = 300 pixels per inch + Width unit = inch + Vertical resolution = 300 pixels per inch + Height unit = inch + 8BIM: [0x0404] Name="" Len=[0x003F] DefinedName="IPTC-NAA record" + IPTC [001:090] Coded Character Set = "%G" + IPTC [002:000] Record Version = 4 + IPTC [002:055] Date Created = "20090719" + IPTC [002:060] Time Created = "170036" + IPTC [002:062] Digital Creation Date = "20090719" + IPTC [002:063] Digital Creation Time = "170036" + 8BIM: [0x040C] Name="" Len=[0x2578] DefinedName="Thumbnail resources" + Format = 1 + Width of thumbnail = 256 pixels + Height of thumbnail = 171 pixels + Widthbytes = 768 bytes + Total size = 131328 bytes + Size after compression = 9564 bytes + Bits per pixel = 24 bits + Number of planes = 1 + JFIF data @ 0x0000293E + 8BIM: [0x0425] Name="" Len=[0x0010] DefinedName="Caption digest" + Caption digest = | 0x52 C5 4C EC 1E FE 25 B8 CA 88 F7 0D 2B 5F 09 F5 | R.L...%.....+_.. + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00004EB6 + Length = 576 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 560 bytes + Preferred CMM Type : 'ADBE' (0x41444245) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 1999-06-03 00:00:00 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Apple Computer, Inc. ('APPL' (0x4150504C)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : 'none' (0x6E6F6E65) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'ADBE' (0x41444245) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x000050F8 + Length = 10738 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + | + | + | + | + | + | + | + | + | + | + | + | + | + | 0, 0 + | 32, 22 + | 64, 56 + | 128, 128 + | 192, 196 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00007AEC + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 9 11 12 16 + DQT, Row #1: 4 5 5 6 8 10 12 12 + DQT, Row #2: 4 5 5 6 10 12 12 12 + DQT, Row #3: 6 6 6 11 12 12 12 12 + DQT, Row #4: 9 8 10 12 12 12 12 12 + DQT, Row #5: 11 10 12 12 12 12 12 12 + DQT, Row #6: 12 12 12 12 12 12 12 12 + DQT, Row #7: 16 12 12 12 12 12 12 12 + Approx quality factor = 88.28 (scaling=23.43 variance=111.68) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 7 7 13 24 20 20 17 17 + DQT, Row #1: 7 12 16 14 14 12 12 12 + DQT, Row #2: 13 16 14 14 12 12 12 12 + DQT, Row #3: 24 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 90.19 (scaling=19.62 variance=201.04) + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x00007B72 + Length = 4 + interval = 160 + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x00007B78 + Length = 14 + DCTEncodeVersion = 100 + APP14Flags0 = 49152 + APP14Flags1 = 0 + ColorTransform = 1 [YCbCr] + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00007B88 + Frame header length = 17 + Precision = 8 + Number of Lines = 853 + Samples per Line = 1280 + Image Size = 1280 x 853 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00007B9B + Huffman table length = 159 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 03 + Codes of length 03 bits (003 total): 01 02 04 + Codes of length 04 bits (001 total): 05 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (001 total): 08 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 006 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 12 21 31 + Codes of length 06 bits (002 total): 05 41 + Codes of length 07 bits (003 total): 13 22 51 + Codes of length 08 bits (006 total): 32 61 71 81 91 A1 + Codes of length 09 bits (005 total): 06 14 23 42 B1 + Codes of length 10 bits (002 total): 52 C1 + Codes of length 11 bits (004 total): 15 33 62 D1 + Codes of length 12 bits (004 total): 07 72 E1 F1 + Codes of length 13 bits (005 total): 16 24 43 82 F0 + Codes of length 14 bits (003 total): 34 92 A2 + Codes of length 15 bits (000 total): + Codes of length 16 bits (011 total): 53 63 C2 25 73 B2 D2 26 54 93 E2 + Total number of codes: 054 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (001 total): 02 + Codes of length 05 bits (000 total): + Codes of length 06 bits (002 total): 12 21 + Codes of length 07 bits (002 total): 03 31 + Codes of length 08 bits (003 total): 13 41 51 + Codes of length 09 bits (001 total): 61 + Codes of length 10 bits (000 total): + Codes of length 11 bits (002 total): 04 71 + Codes of length 12 bits (003 total): 14 22 81 + Codes of length 13 bits (001 total): 32 + Codes of length 14 bits (001 total): 42 + Codes of length 15 bits (001 total): 91 + Codes of length 16 bits (000 total): + Total number of codes: 020 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00007C3C + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00007C4A + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00032604.0 + + Compression stats: + Compression Ratio: 18.77:1 + Bits per pixel: 1.28:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 8237 ( 48%) + # codes of length 03 bits: 7451 ( 44%) + # codes of length 04 bits: 930 ( 5%) + # codes of length 05 bits: 300 ( 2%) + # codes of length 06 bits: 197 ( 1%) + # codes of length 07 bits: 5 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 16681 ( 49%) + # codes of length 02 bits: 10125 ( 30%) + # codes of length 03 bits: 5138 ( 15%) + # codes of length 04 bits: 1825 ( 5%) + # codes of length 05 bits: 432 ( 1%) + # codes of length 06 bits: 39 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 104267 ( 49%) + # codes of length 03 bits: 23564 ( 11%) + # codes of length 04 bits: 44372 ( 21%) + # codes of length 05 bits: 19037 ( 9%) + # codes of length 06 bits: 5565 ( 3%) + # codes of length 07 bits: 5437 ( 3%) + # codes of length 08 bits: 5066 ( 2%) + # codes of length 09 bits: 2163 ( 1%) + # codes of length 10 bits: 491 ( 0%) + # codes of length 11 bits: 407 ( 0%) + # codes of length 12 bits: 211 ( 0%) + # codes of length 13 bits: 115 ( 0%) + # codes of length 14 bits: 36 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 26 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 34240 ( 51%) + # codes of length 02 bits: 15658 ( 24%) + # codes of length 03 bits: 7424 ( 11%) + # codes of length 04 bits: 3865 ( 6%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 3125 ( 5%) + # codes of length 07 bits: 1208 ( 2%) + # codes of length 08 bits: 744 ( 1%) + # codes of length 09 bits: 113 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 60 ( 0%) + # codes of length 12 bits: 60 ( 0%) + # codes of length 13 bits: 9 ( 0%) + # codes of length 14 bits: 4 ( 0%) + # codes of length 15 bits: 1 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[122] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 714, -42, 42] RGB=[224,215,206] @ MCU[113, 24] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 106 + Next position in scan buffer: Offset 0x00032604.0 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00032604 + + +*** Embedded JPEG Thumbnail *** + Offset: 0x00000340 + Length: 0x0000255C (9564) + + * Embedded Thumb Marker: SOI + + * Embedded Thumb Marker: DQT + Length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance, typically) + DQT, Row #0: 6 4 4 6 9 11 12 16 + DQT, Row #1: 4 5 5 6 8 10 12 12 + DQT, Row #2: 4 5 5 6 10 12 12 12 + DQT, Row #3: 6 6 6 11 12 12 12 12 + DQT, Row #4: 9 8 10 12 12 12 12 12 + DQT, Row #5: 11 10 12 12 12 12 12 12 + DQT, Row #6: 12 12 12 12 12 12 12 12 + DQT, Row #7: 16 12 12 12 12 12 12 12 + ---- + Precision=8 bits + Destination ID=1 (Chrominance, typically) + DQT, Row #0: 7 7 13 24 20 20 17 17 + DQT, Row #1: 7 12 16 14 14 12 12 12 + DQT, Row #2: 13 16 14 14 12 12 12 12 + DQT, Row #3: 24 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + + * Embedded Thumb Marker: DRI + Length = 4 + + * Embedded Thumb Marker: APP14 + Length = 14 + + * Embedded Thumb Marker: SOF + Frame header length = 17 + Precision = 8 + Number of Lines = 171 + Samples per Line = 256 + Image Size = 256 x 171 + + * Embedded Thumb Marker: DHT + Length = 148 + + * Embedded Thumb Marker: SOS + Skipping scan data + Skipped 9212 bytes + + * Embedded Thumb Marker: EOI + + * Embedded Thumb Signature: 01180AF3DE63318828A86409EF4013DD + +*** Searching Compression Signatures *** + + Signature: 01180AF3DE63318828A86409EF4013DD + Signature (Rotated): 01180AF3DE63318828A86409EF4013DD + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: OK [Canon] [Canon EOS DIGITAL REBEL XSi] + EXIF Makernotes: NONE + EXIF Software: OK [Adobe Photoshop Camera Raw 9.8 (Windows)] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[Adobe Photoshop ] [Save As 08 ] + + NOTE: EXIF Software field recognized as from editor + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + Appears to be new signature for known software. + If the camera/software doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/MultiScanBaselineCMYK.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/MultiScanBaselineCMYK.jpg.txt new file mode 100644 index 0000000000..cd415a201a --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/MultiScanBaselineCMYK.jpg.txt @@ -0,0 +1,282 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\MultiScanBaselineCMYK.jpg] + Filesize: [47443] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x00000014 + Length = 14 + DCTEncodeVersion = 25600 + APP14Flags0 = 0 + APP14Flags1 = 0 + ColorTransform = 2 [YCCK] + +*** Marker: COM (Comment) (xFFFE) *** + OFFSET: 0x00000024 + Comment length = 38 + Comment=Created by fCoder Graphics Processor + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0000004C + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 5 3 3 5 7 12 15 18 + DQT, Row #1: 4 4 4 6 8 17 18 17 + DQT, Row #2: 4 4 5 7 12 17 21 17 + DQT, Row #3: 4 5 7 9 15 26 24 19 + DQT, Row #4: 5 7 11 17 20 33 31 23 + DQT, Row #5: 7 11 17 19 24 31 34 28 + DQT, Row #6: 15 19 23 26 31 36 36 30 + DQT, Row #7: 22 28 29 29 34 30 31 30 + Approx quality factor = 84.93 (scaling=30.13 variance=1.05) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000091 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 5 5 7 14 30 30 30 30 + DQT, Row #1: 5 6 8 20 30 30 30 30 + DQT, Row #2: 7 8 17 30 30 30 30 30 + DQT, Row #3: 14 20 30 30 30 30 30 30 + DQT, Row #4: 30 30 30 30 30 30 30 30 + DQT, Row #5: 30 30 30 30 30 30 30 30 + DQT, Row #6: 30 30 30 30 30 30 30 30 + DQT, Row #7: 30 30 30 30 30 30 30 30 + Approx quality factor = 84.93 (scaling=30.15 variance=0.29) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x000000D6 + Frame header length = 20 + Precision = 8 + Number of Lines = 842 + Samples per Line = 595 + Image Size = 595 x 842 + Raw Image Orientation = Portrait + Number of Img components = 4 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Cr) + Component[4]: ID=0x04, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (K) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000EC + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000010D + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000001C4 + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000001E5 + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000029C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support CMYK files yet. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00005825 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support CMYK files yet. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000766A + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support CMYK files yet. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000A1FA + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x04, table=0(DC),0(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support CMYK files yet. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000B951 + + +*** Searching Compression Signatures *** + + Signature: 0155D875C95B74D0F3C5835A62516F48 + Signature (Rotated): 01D38A25358EB7649A254E19F1D46600 + File Offset: 0 bytes + Chroma subsampling: ?x? + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[Nokia ] [N73 ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 8100 ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + SW :[IJG Library ] [085 ] + SW :[Picasa ] [085 (Normal) ] + SW :[ZoomBrowser EX ] [medium ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [085 ] + SW :[IrfanView ] [085 ] + SW :[idImager ] [085 ] + SW :[FastStone Image Viewer ] [085 ] + SW :[NeatImage ] [085 ] + SW :[Paint.NET ] [085 ] + SW :[Photomatix ] [085 ] + SW :[XnView ] [085 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Snake.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Snake.jpg.txt new file mode 100644 index 0000000000..926da026fd --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Snake.jpg.txt @@ -0,0 +1,683 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Snake.jpg] + Filesize: [165200] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000002 + Length = 11941 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000014 + Dir Length = 0x0008 + [Make ] = "Canon" + [Model ] = "Canon EOS DIGITAL REBEL XSi" + [XResolution ] = 300/1 + [YResolution ] = 300/1 + [ResolutionUnit ] = Inch + [Software ] = "Adobe Photoshop Camera Raw 9.8 (Windows)" + [DateTime ] = "2016:12:29 12:57:50" + [ExifOffset ] = @ 0x00DE + Offset to Next IFD = 0x000002D6 + + EXIF IFD1 @ Absolute 0x000002E2 + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x0334 = @ 0x0340 + [JpegIFByteCount ] = 0x[00002B69] / 11113 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000EA + Dir Length = 0x001B + [ExposureTime ] = 1/25 s + [FNumber ] = F4.0 + [ExposureProgram ] = Shutter priority + [ISOSpeedRatings ] = 250 + [ExifVersion ] = 02.30 + [DateTimeOriginal ] = "2009:07:19 13:25:29" + [DateTimeDigitized ] = "2009:07:19 13:25:29" + [ShutterSpeedValue ] = 4643856/1000000 + [ApertureValue ] = 4/1 + [ExposureBiasValue ] = 0.00 eV + [MaxApertureValue ] = 4/1 + [MeteringMode ] = Pattern + [Flash ] = Flash did not fire + [FocalLength ] = 200 mm + [SubSecTimeOriginal ] = "03" + [SubSecTimeDigitized ] = "03" + [ColorSpace ] = Uncalibrated + [FocalPlaneXResolution ] = 4272000/878 + [FocalPlaneYResolution ] = 2848000/584 + [FocalPlaneResolutionUnit ] = Inch + [CustomRendered ] = Normal process + [ExposureMode ] = Auto exposure + [WhiteBalance ] = Auto white balance + [SceneCaptureType ] = Standard + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x00002EA9 + Length = 11302 + Identifier = [Photoshop 3.0] + 8BIM: [0x03ED] Name="" Len=[0x0010] DefinedName="ResolutionInfo structure" + Horizontal resolution = 300 pixels per inch + Width unit = inch + Vertical resolution = 300 pixels per inch + Height unit = inch + 8BIM: [0x0404] Name="" Len=[0x003F] DefinedName="IPTC-NAA record" + IPTC [001:090] Coded Character Set = "%G" + IPTC [002:000] Record Version = 4 + IPTC [002:055] Date Created = "20090719" + IPTC [002:060] Time Created = "132529" + IPTC [002:062] Digital Creation Date = "20090719" + IPTC [002:063] Digital Creation Time = "132529" + 8BIM: [0x040C] Name="" Len=[0x2B85] DefinedName="Thumbnail resources" + Format = 1 + Width of thumbnail = 256 pixels + Height of thumbnail = 171 pixels + Widthbytes = 768 bytes + Total size = 131328 bytes + Size after compression = 11113 bytes + Bits per pixel = 24 bits + Number of planes = 1 + JFIF data @ 0x00002F4B + 8BIM: [0x0425] Name="" Len=[0x0010] DefinedName="Caption digest" + Caption digest = | 0xEE 2F A2 47 C5 F8 ED 07 08 CD FF 82 A0 D1 7F F2 | ./.G............ + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00005AD1 + Length = 576 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 560 bytes + Preferred CMM Type : 'ADBE' (0x41444245) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 1999-06-03 00:00:00 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Apple Computer, Inc. ('APPL' (0x4150504C)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : 'none' (0x6E6F6E65) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'ADBE' (0x41444245) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00005D13 + Length = 10733 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + | + | + | + | + | + | + | + | + | + | + | + | + | + | 0, 0 + | 32, 22 + | 64, 56 + | 128, 128 + | 192, 196 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00008702 + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 9 11 12 16 + DQT, Row #1: 4 5 5 6 8 10 12 12 + DQT, Row #2: 4 5 5 6 10 12 12 12 + DQT, Row #3: 6 6 6 11 12 12 12 12 + DQT, Row #4: 9 8 10 12 12 12 12 12 + DQT, Row #5: 11 10 12 12 12 12 12 12 + DQT, Row #6: 12 12 12 12 12 12 12 12 + DQT, Row #7: 16 12 12 12 12 12 12 12 + Approx quality factor = 88.28 (scaling=23.43 variance=111.68) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 7 7 13 24 20 20 17 17 + DQT, Row #1: 7 12 16 14 14 12 12 12 + DQT, Row #2: 13 16 14 14 12 12 12 12 + DQT, Row #3: 24 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 90.19 (scaling=19.62 variance=201.04) + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x00008788 + Length = 4 + interval = 160 + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x0000878E + Length = 14 + DCTEncodeVersion = 100 + APP14Flags0 = 49152 + APP14Flags1 = 0 + ColorTransform = 1 [YCbCr] + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000879E + Frame header length = 17 + Precision = 8 + Number of Lines = 853 + Samples per Line = 1280 + Image Size = 1280 x 853 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000087B1 + Huffman table length = 153 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 02 03 + Codes of length 03 bits (003 total): 01 04 05 + Codes of length 04 bits (001 total): 00 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (001 total): 08 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (001 total): 06 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 007 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (002 total): 00 03 + Codes of length 04 bits (002 total): 04 11 + Codes of length 05 bits (001 total): 21 + Codes of length 06 bits (003 total): 05 12 31 + Codes of length 07 bits (003 total): 13 41 51 + Codes of length 08 bits (003 total): 06 22 61 + Codes of length 09 bits (003 total): 14 32 71 + Codes of length 10 bits (003 total): 42 81 91 + Codes of length 11 bits (003 total): 15 23 A1 + Codes of length 12 bits (004 total): 07 52 B1 C1 + Codes of length 13 bits (001 total): 33 + Codes of length 14 bits (002 total): 24 43 + Codes of length 15 bits (002 total): 62 D1 + Codes of length 16 bits (011 total): 16 34 72 E1 25 53 63 92 82 A2 F0 + Total number of codes: 045 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (001 total): 02 + Codes of length 05 bits (000 total): + Codes of length 06 bits (003 total): 03 12 21 + Codes of length 07 bits (001 total): 31 + Codes of length 08 bits (000 total): + Codes of length 09 bits (002 total): 04 41 + Codes of length 10 bits (003 total): 13 22 51 + Codes of length 11 bits (000 total): + Codes of length 12 bits (003 total): 32 61 71 + Codes of length 13 bits (000 total): + Codes of length 14 bits (003 total): 05 14 42 + Codes of length 15 bits (000 total): + Codes of length 16 bits (003 total): 81 52 62 + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000884C + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x0000885A + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0002854E.0 + + Compression stats: + Compression Ratio: 25.14:1 + Bits per pixel: 0.95:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 7183 ( 42%) + # codes of length 03 bits: 7286 ( 43%) + # codes of length 04 bits: 1551 ( 9%) + # codes of length 05 bits: 856 ( 5%) + # codes of length 06 bits: 218 ( 1%) + # codes of length 07 bits: 26 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 12266 ( 36%) + # codes of length 02 bits: 11394 ( 33%) + # codes of length 03 bits: 6548 ( 19%) + # codes of length 04 bits: 2911 ( 9%) + # codes of length 05 bits: 875 ( 3%) + # codes of length 06 bits: 241 ( 1%) + # codes of length 07 bits: 5 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 59325 ( 45%) + # codes of length 03 bits: 31160 ( 24%) + # codes of length 04 bits: 18131 ( 14%) + # codes of length 05 bits: 4871 ( 4%) + # codes of length 06 bits: 9522 ( 7%) + # codes of length 07 bits: 4029 ( 3%) + # codes of length 08 bits: 2270 ( 2%) + # codes of length 09 bits: 1006 ( 1%) + # codes of length 10 bits: 515 ( 0%) + # codes of length 11 bits: 268 ( 0%) + # codes of length 12 bits: 195 ( 0%) + # codes of length 13 bits: 24 ( 0%) + # codes of length 14 bits: 29 ( 0%) + # codes of length 15 bits: 20 ( 0%) + # codes of length 16 bits: 26 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 34240 ( 51%) + # codes of length 02 bits: 16000 ( 24%) + # codes of length 03 bits: 5994 ( 9%) + # codes of length 04 bits: 5610 ( 8%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 3610 ( 5%) + # codes of length 07 bits: 600 ( 1%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 410 ( 1%) + # codes of length 10 bits: 200 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 70 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 17 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 6 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[110] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 954, 14, -14] RGB=[244,248,248] @ MCU[124, 21] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 106 + Next position in scan buffer: Offset 0x0002854D.3 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0002854E + + +*** Embedded JPEG Thumbnail *** + Offset: 0x00000340 + Length: 0x00002B69 (11113) + + * Embedded Thumb Marker: SOI + + * Embedded Thumb Marker: DQT + Length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance, typically) + DQT, Row #0: 6 4 4 6 9 11 12 16 + DQT, Row #1: 4 5 5 6 8 10 12 12 + DQT, Row #2: 4 5 5 6 10 12 12 12 + DQT, Row #3: 6 6 6 11 12 12 12 12 + DQT, Row #4: 9 8 10 12 12 12 12 12 + DQT, Row #5: 11 10 12 12 12 12 12 12 + DQT, Row #6: 12 12 12 12 12 12 12 12 + DQT, Row #7: 16 12 12 12 12 12 12 12 + ---- + Precision=8 bits + Destination ID=1 (Chrominance, typically) + DQT, Row #0: 7 7 13 24 20 20 17 17 + DQT, Row #1: 7 12 16 14 14 12 12 12 + DQT, Row #2: 13 16 14 14 12 12 12 12 + DQT, Row #3: 24 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + + * Embedded Thumb Marker: DRI + Length = 4 + + * Embedded Thumb Marker: APP14 + Length = 14 + + * Embedded Thumb Marker: SOF + Frame header length = 17 + Precision = 8 + Number of Lines = 171 + Samples per Line = 256 + Image Size = 256 x 171 + + * Embedded Thumb Marker: DHT + Length = 150 + + * Embedded Thumb Marker: SOS + Skipping scan data + Skipped 10759 bytes + + * Embedded Thumb Marker: EOI + + * Embedded Thumb Signature: 01180AF3DE63318828A86409EF4013DD + +*** Searching Compression Signatures *** + + Signature: 01180AF3DE63318828A86409EF4013DD + Signature (Rotated): 01180AF3DE63318828A86409EF4013DD + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: OK [Canon] [Canon EOS DIGITAL REBEL XSi] + EXIF Makernotes: NONE + EXIF Software: OK [Adobe Photoshop Camera Raw 9.8 (Windows)] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[Adobe Photoshop ] [Save As 08 ] + + NOTE: EXIF Software field recognized as from editor + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + Appears to be new signature for known software. + If the camera/software doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/badeof.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/badeof.jpg.txt new file mode 100644 index 0000000000..97be4853e6 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/badeof.jpg.txt @@ -0,0 +1,347 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\badeof.jpg] + Filesize: [5770] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 8 6 5 8 12 20 26 31 + DQT, Row #1: 6 6 7 10 13 29 30 28 + DQT, Row #2: 7 7 8 12 20 29 35 28 + DQT, Row #3: 7 9 11 15 26 44 40 31 + DQT, Row #4: 9 11 19 28 34 55 52 39 + DQT, Row #5: 12 18 28 32 41 52 57 46 + DQT, Row #6: 25 32 39 44 52 61 60 51 + DQT, Row #7: 36 46 48 49 56 50 52 50 + Approx quality factor = 74.75 (scaling=50.51 variance=0.81) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + Approx quality factor = 74.74 (scaling=50.52 variance=0.19) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 149 + Samples per Line = 227 + Image Size = 227 x 149 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000D2 + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000189 + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000001AA + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000261 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x0000026F + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + + Compression stats: + Compression Ratio: 19.73:1 + Bits per pixel: 1.22:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 88 ( 15%) + # codes of length 03 bits: 409 ( 68%) + # codes of length 04 bits: 66 ( 11%) + # codes of length 05 bits: 33 ( 6%) + # codes of length 06 bits: 4 ( 1%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 134 ( 45%) + # codes of length 03 bits: 68 ( 23%) + # codes of length 04 bits: 60 ( 20%) + # codes of length 05 bits: 26 ( 9%) + # codes of length 06 bits: 12 ( 4%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2706 ( 48%) + # codes of length 03 bits: 636 ( 11%) + # codes of length 04 bits: 1331 ( 23%) + # codes of length 05 bits: 473 ( 8%) + # codes of length 06 bits: 196 ( 3%) + # codes of length 07 bits: 169 ( 3%) + # codes of length 08 bits: 66 ( 1%) + # codes of length 09 bits: 60 ( 1%) + # codes of length 10 bits: 28 ( 0%) + # codes of length 11 bits: 14 ( 0%) + # codes of length 12 bits: 4 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 5 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 697 ( 46%) + # codes of length 03 bits: 243 ( 16%) + # codes of length 04 bits: 294 ( 19%) + # codes of length 05 bits: 164 ( 11%) + # codes of length 06 bits: 68 ( 4%) + # codes of length 07 bits: 5 ( 0%) + # codes of length 08 bits: 35 ( 2%) + # codes of length 09 bits: 4 ( 0%) + # codes of length 10 bits: 2 ( 0%) + # codes of length 11 bits: 1 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[107] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1008, -9, 0] RGB=[254,254,250] @ MCU[ 4, 8] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00001687.2 + + +*** Skipped 1 marker pad bytes *** +*** Marker: ??? (Unknown) (xFF00) *** + OFFSET: 0x00001689 + WARNING: Unknown marker [0xFF00] + Stopping decode + Use [Img Search Fwd/Rev] to locate other valid embedded JPEGs + +*** Searching Compression Signatures *** + + Signature: 0182408A81A4ABF04D4A34A8A5E98C58 + Signature (Rotated): 012D821C6AB210E2A753BE053B8F55D0 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[SONY ] [CYBERSHOT U ] [ ] Yes + SW :[Adobe Photoshop 7.0 ] [Save As 07 ] + SW :[Apple Quicktime ] [0466-0467 ] + SW :[Digital Photo Professiona] [05 ] + SW :[IJG Library ] [075 ] + SW :[MS Paint ] [ ] + SW :[MS Visio ] [ ] + SW :[ZoomBrowser EX ] [low ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [075 ] + SW :[IrfanView ] [075 ] + SW :[idImager ] [075 ] + SW :[FastStone Image Viewer ] [075 ] + SW :[NeatImage ] [075 ] + SW :[Paint.NET ] [075 ] + SW :[Photomatix ] [075 ] + SW :[XnView ] [075 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + + +*** Additional Info *** +NOTE: Data exists after EOF, range: 0x00000000-0x0000168A (5770 bytes) diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/badrst.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/badrst.jpg.txt new file mode 100644 index 0000000000..cb74eb88f5 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/badrst.jpg.txt @@ -0,0 +1,434 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\badrst.jpg] + Filesize: [74497] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 96 x 96 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 8628 + Identifier = [Exif] + Identifier TIFF = 0x[4D4D002A 00000008] + Endian = Motorola (big) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0003 + [Orientation ] = 1 = Row 0: top, Col 0: left + [ExifOffset ] = @ 0x083E + Offset to Next IFD = 0x000010B6 + + EXIF IFD1 @ Absolute 0x000010D4 + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 96/1 + [YResolution ] = 96/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x1114 = @ 0x1132 + [JpegIFByteCount ] = 0x[00001097] / 4247 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x0000085C + Dir Length = 0x0005 + [DateTimeOriginal ] = "2016:02:28 11:17:08" + [DateTimeDigitized ] = "2016:02:28 11:17:08" + [SubSecTimeOriginal ] = "06" + [SubSecTimeDigitized ] = "06" + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x000021CA + Length = 2464 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + | + |2016-02-28T11:17:08.057 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00002B6C + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 5 8 10 12 + DQT, Row #1: 2 2 3 4 5 12 12 11 + DQT, Row #2: 3 3 3 5 8 11 14 11 + DQT, Row #3: 3 3 4 6 10 17 16 12 + DQT, Row #4: 4 4 7 11 14 22 21 15 + DQT, Row #5: 5 7 11 13 16 21 23 18 + DQT, Row #6: 10 13 16 17 21 24 24 20 + DQT, Row #7: 14 18 19 20 22 20 21 20 + Approx quality factor = 90.06 (scaling=19.88 variance=1.14) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00002BB1 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 3 4 5 9 20 20 20 20 + DQT, Row #1: 4 4 5 13 20 20 20 20 + DQT, Row #2: 5 5 11 20 20 20 20 20 + DQT, Row #3: 9 13 20 20 20 20 20 20 + DQT, Row #4: 20 20 20 20 20 20 20 20 + DQT, Row #5: 20 20 20 20 20 20 20 20 + DQT, Row #6: 20 20 20 20 20 20 20 20 + DQT, Row #7: 20 20 20 20 20 20 20 20 + Approx quality factor = 89.93 (scaling=20.14 variance=0.34) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00002BF6 + Frame header length = 17 + Precision = 8 + Number of Lines = 480 + Samples per Line = 640 + Image Size = 640 x 480 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002C09 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002C2A + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002CE1 + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002D02 + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x00002DB9 + Length = 4 + interval = 600 + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002DBF + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00002DCD + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Expect Restart interval elapsed @ 0x00008802.4 + ERROR: Restart marker not detected +*** ERROR: Can't find huffman bitstring @ 0x00008802.5, table 0, value [0xffffffe0] +*** ERROR: Bad huffman code @ 0x00008802.4 +*** ERROR: Bad scan data in MCU(0,15): Lum CSS(0,0) @ Offset 0x00008802.5 + MCU located at pixel=(0,240) +*** ERROR: Can't find huffman bitstring @ 0x00008802.6, table 0, value [0xffffffc0] +*** ERROR: Bad huffman code @ 0x00008802.5 +*** ERROR: Bad scan data in MCU(0,15): Lum CSS(1,0) @ Offset 0x00008802.6 + MCU located at pixel=(8,240) +*** ERROR: Can't find huffman bitstring @ 0x00008802.7, table 0, value [0xffffff80] +*** ERROR: Bad huffman code @ 0x00008802.6 +*** ERROR: Bad scan data in MCU(0,15): Lum CSS(0,1) @ Offset 0x00008802.7 + MCU located at pixel=(0,248) +*** ERROR: Can't find huffman bitstring @ 0x00008803.0, table 0, value [0xffffffff] +*** ERROR: Bad huffman code @ 0x00008802.7 +*** ERROR: Bad scan data in MCU(0,15): Lum CSS(1,1) @ Offset 0x00008803.0 + MCU located at pixel=(8,248) +*** ERROR: Can't find huffman bitstring @ 0x00008803.1, table 1, value [0xfffffffe] +*** ERROR: Bad huffman code @ 0x00008803.0 +*** ERROR: Bad scan data in MCU(0,15): Chr(Cb) CSS(0,0) @ Offset 0x00008803.1 + MCU located at pixel=(0,240) +*** ERROR: Can't find huffman bitstring @ 0x00008803.2, table 1, value [0xfffffffc] +*** ERROR: Bad huffman code @ 0x00008803.1 +*** ERROR: Bad scan data in MCU(0,15): Chr(Cr) CSS(0,0) @ Offset 0x00008803.2 + MCU located at pixel=(0,240) +*** ERROR: Can't find huffman bitstring @ 0x00008803.3, table 0, value [0xfffffff8] +*** ERROR: Bad huffman code @ 0x00008803.2 + Only reported first 20 instances of this message... + + Compression stats: + Compression Ratio: 14.80:1 + Bits per pixel: 1.62:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 40 ( 1%) + # codes of length 02 bits: 202 ( 4%) + # codes of length 03 bits: 3515 ( 73%) + # codes of length 04 bits: 423 ( 9%) + # codes of length 05 bits: 338 ( 7%) + # codes of length 06 bits: 228 ( 5%) + # codes of length 07 bits: 54 ( 1%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 20 ( 1%) + # codes of length 02 bits: 1657 ( 69%) + # codes of length 03 bits: 311 ( 13%) + # codes of length 04 bits: 232 ( 10%) + # codes of length 05 bits: 123 ( 5%) + # codes of length 06 bits: 49 ( 2%) + # codes of length 07 bits: 8 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 32135 ( 43%) + # codes of length 03 bits: 8668 ( 12%) + # codes of length 04 bits: 15771 ( 21%) + # codes of length 05 bits: 7559 ( 10%) + # codes of length 06 bits: 2518 ( 3%) + # codes of length 07 bits: 3834 ( 5%) + # codes of length 08 bits: 1387 ( 2%) + # codes of length 09 bits: 1122 ( 2%) + # codes of length 10 bits: 562 ( 1%) + # codes of length 11 bits: 234 ( 0%) + # codes of length 12 bits: 131 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 57 ( 0%) + # codes of length 16 bits: 286 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 4525 ( 57%) + # codes of length 03 bits: 1153 ( 14%) + # codes of length 04 bits: 1341 ( 17%) + # codes of length 05 bits: 543 ( 7%) + # codes of length 06 bits: 281 ( 4%) + # codes of length 07 bits: 14 ( 0%) + # codes of length 08 bits: 93 ( 1%) + # codes of length 09 bits: 23 ( 0%) + # codes of length 10 bits: 3 ( 0%) + # codes of length 11 bits: 3 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 2 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[103] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1014, -3, -27] RGB=[248,255,252] @ MCU[ 0, 13] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 1 + Next position in scan buffer: Offset 0x0001210E.0 + + +*** Skipped 10 marker pad bytes *** +*** Marker: RST# *** + OFFSET: 0x0000880D + WARNING: Restart marker [0xFFD0] detected outside scan + Stopping decode + Use [Img Search Fwd/Rev] to locate other valid embedded JPEGs + +*** Searching Compression Signatures *** + + Signature: 013BA18D5561625796E986FDBC09F846 + Signature (Rotated): 01AC57E12793DFA7C46C704625C5AF0F + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[??? ] [Treo 680 ] [ ] Yes + CAM:[Canon ] [Canon PowerShot Pro1 ] [fine ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E3100 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5000 ] [FINE ] No + CAM:[NIKON ] [E5700 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[NIKON ] [E885 ] [FINE ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 9530 ] [Superfine ] Yes + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-W1 ] [ ] No + CAM:[SONY ] [SONY ] [ ] No + SW :[ACDSee ] [ ] + SW :[FixFoto ] [fine ] + SW :[IJG Library ] [090 ] + SW :[ZoomBrowser EX ] [high ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [090 ] + SW :[IrfanView ] [090 ] + SW :[idImager ] [090 ] + SW :[FastStone Image Viewer ] [090 ] + SW :[NeatImage ] [090 ] + SW :[Paint.NET ] [090 ] + SW :[Photomatix ] [090 ] + SW :[XnView ] [090 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + + +*** Additional Info *** +NOTE: Data exists after EOF, range: 0x00000000-0x00012301 (74497 bytes) diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/cmyk.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/cmyk.jpg.txt new file mode 100644 index 0000000000..68777cc049 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/cmyk.jpg.txt @@ -0,0 +1,435 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\cmyk.jpg] + Filesize: [2531270] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 300 x 300 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x00000014 + Length = 14 + DCTEncodeVersion = 100 + APP14Flags0 = 0 + APP14Flags1 = 0 + ColorTransform = 0 [Unknown (RGB or CMYK)] + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00000024 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 29 + Profile Size : 1829080 bytes + Preferred CMM Type : 'HDM ' (0x48444D20) + Profile Version : 0.2.4.0 (0x02400000) + Profile Device/Class : Output Device profile ('prtr' (0x70727472)) + Data Colour Space : cmykData ('CMYK' (0x434D594B)) + Profile connection space (PCS) : 'Lab ' (0x4C616220) + Profile creation date : 2007-02-28 08:00:00 + Profile file signature : 'acsp' (0x61637370) + Primary platform : ? (0x00000000) ('....' (0x00000000)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : '....' (0x00000000) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Media-Relative Colorimetric + Profile creator : 'HDM ' (0x48444D20) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0000FE1E + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 2 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0001FC18 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 3 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0002FA12 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 4 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0003F80C + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 5 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0004F606 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 6 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0005F400 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 7 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0006F1FA + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 8 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0007EFF4 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 9 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0008EDEE + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 10 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0009EBE8 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 11 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000AE9E2 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 12 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000BE7DC + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 13 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000CE5D6 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 14 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000DE3D0 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 15 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000EE1CA + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 16 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000FDFC4 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 17 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0010DDBE + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 18 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0011DBB8 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 19 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0012D9B2 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 20 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0013D7AC + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 21 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0014D5A6 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 22 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0015D3A0 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 23 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0016D19A + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 24 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0017CF94 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 25 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0018CD8E + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 26 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0019CB88 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 27 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x001AC982 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 28 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x001BC77C + Length = 9096 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 29 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x001BEB06 + Length = 188 + Identifier = [Photoshop 3.0] + 8BIM: [0x0404] Name="" Len=[0x009F] DefinedName="IPTC-NAA record" + IPTC [002:025] Keywords = "jpeg, productbeelden, productie, ptc, ptc369x1, pulsar" + IPTC [002:210] ? = ??? + IPTC [002:211] ? = ??? + IPTC [002:212] ? = ??? + IPTC [002:213] ? = ??? + IPTC [002:214] ? = ??? + IPTC [002:215] ? = ??? + IPTC [002:216] ? = ??? + IPTC [002:217] ? = ??? + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x001BEBC4 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 1 1 1 + DQT, Row #4: 1 1 1 1 1 1 1 1 + DQT, Row #5: 1 1 1 1 1 1 1 1 + DQT, Row #6: 1 1 1 1 1 1 1 1 + DQT, Row #7: 1 1 1 1 1 1 1 1 + Approx quality factor = 100.00 (scaling=2.99 variance=6.13) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x001BEC09 + Frame header length = 20 + Precision = 8 + Number of Lines = 900 + Samples per Line = 414 + Image Size = 414 x 900 + Raw Image Orientation = Portrait + Number of Img components = 4 + Component[1]: ID=0x43, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Y) + Component[2]: ID=0x4D, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Cb) + Component[3]: ID=0x59, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Cr) + Component[4]: ID=0x4B, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (K) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x001BEC1F + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x001BEC40 + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x001BECF7 + Scan header length = 14 + Number of img components = 4 + Component[1]: selector=0x43, table=0(DC),0(AC) + Component[2]: selector=0x4D, table=0(DC),0(AC) + Component[3]: selector=0x59, table=0(DC),0(AC) + Component[4]: selector=0x4B, table=0(DC),0(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support CMYK files yet. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00269FC4 + + +*** Searching Compression Signatures *** + + Signature: 01BC2BB6764A7F9709F829E766D93AAE + Signature (Rotated): 01BC2BB6764A7F9709F829E766D93AAE + File Offset: 0 bytes + Chroma subsampling: ?x? + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[IJG Library ] [100 Gray ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [100 Gray ] + SW :[IrfanView ] [100 Gray ] + SW :[idImager ] [100 Gray ] + SW :[FastStone Image Viewer ] [100 Gray ] + SW :[NeatImage ] [100 Gray ] + SW :[Paint.NET ] [100 Gray ] + SW :[Photomatix ] [100 Gray ] + SW :[XnView ] [100 Gray ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/exif.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/exif.jpg.txt new file mode 100644 index 0000000000..df54994c5e --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/exif.jpg.txt @@ -0,0 +1,454 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\exif.jpg] + Filesize: [32764] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 7678 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0009 + [Make ] = "Canon" + [Model ] = "Canon PowerShot S40" + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 180/1 + [YResolution ] = 180/1 + [ResolutionUnit ] = Inch + [DateTime ] = "2003:12:14 12:01:44" + [YCbCrPositioning ] = Centered + [ExifOffset ] = @ 0x00C4 + Offset to Next IFD = 0x000005BE + + EXIF IFD1 @ Absolute 0x000005DC + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 180/1 + [YResolution ] = 180/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x07F4 = @ 0x0812 + [JpegIFByteCount ] = 0x[00001548] / 5448 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000E2 + Dir Length = 0x001F + [ExposureTime ] = 1/500 s + [FNumber ] = F4.9 + [ExifVersion ] = 02.20 + [DateTimeOriginal ] = "2003:12:14 12:01:44" + [DateTimeDigitized ] = "2003:12:14 12:01:44" + [ComponentsConfiguration ] = [Y Cb Cr .] + [CompressedBitsPerPixel ] = 5/1 + [ShutterSpeedValue ] = 287/32 + [ApertureValue ] = 149/32 + [ExposureBiasValue ] = 0.00 eV + [MaxApertureValue ] = 194698/65536 + [MeteringMode ] = CenterWeightedAverage + [Flash ] = Flash did not fire + [FocalLength ] = 21 mm + [MakerNote ] = @ 0x03AE + [UserComment ] = "" + [FlashPixVersion ] = 01.00 + [ColorSpace ] = sRGB + [ExifImageWidth ] = 2272 + [ExifImageHeight ] = 1704 + [ExifInteroperabilityOffset ] = @ 0x0588 + [FocalPlaneXResolution ] = 2272000/280 + [FocalPlaneYResolution ] = 1704000/210 + [FocalPlaneResolutionUnit ] = Inch + [SensingMethod ] = One-chip color area sensor + [FileSource ] = DSC + [CustomRendered ] = Normal process + [ExposureMode ] = Auto exposure + [WhiteBalance ] = Auto white balance + [DigitalZoomRatio ] = 2272/2272 + [SceneCaptureType ] = Standard + + EXIF MakerIFD @ Absolute 0x000003CC + Makernote decode option not enabled. + + EXIF InteropIFD @ Absolute 0x000005A6 + Dir Length = 0x0004 + [InteroperabilityIndex ] = "R98" + [InteroperabilityVersion ] = 01.00 + [RelatedImageWidth ] = 2272 + [RelatedImageLength ] = 1704 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00001E14 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 8 6 5 8 12 20 26 31 + DQT, Row #1: 6 6 7 10 13 29 30 28 + DQT, Row #2: 7 7 8 12 20 29 35 28 + DQT, Row #3: 7 9 11 15 26 44 40 31 + DQT, Row #4: 9 11 19 28 34 55 52 39 + DQT, Row #5: 12 18 28 32 41 52 57 46 + DQT, Row #6: 25 32 39 44 52 61 60 51 + DQT, Row #7: 36 46 48 49 56 50 52 50 + Approx quality factor = 74.75 (scaling=50.51 variance=0.81) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00001E59 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + Approx quality factor = 74.74 (scaling=50.52 variance=0.19) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00001E9E + Frame header length = 17 + Precision = 8 + Number of Lines = 360 + Samples per Line = 480 + Image Size = 480 x 360 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00001EB1 + Huffman table length = 28 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 03 + Codes of length 03 bits (005 total): 01 02 04 05 06 + Codes of length 04 bits (001 total): 00 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00001ECF + Huffman table length = 65 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (002 total): 12 21 + Codes of length 06 bits (004 total): 05 31 41 51 + Codes of length 07 bits (004 total): 13 22 61 71 + Codes of length 08 bits (004 total): 06 32 81 91 + Codes of length 09 bits (004 total): 14 42 A1 B1 + Codes of length 10 bits (004 total): 23 52 C1 D1 + Codes of length 11 bits (005 total): 07 15 33 62 E1 + Codes of length 12 bits (003 total): 43 72 F0 + Codes of length 13 bits (003 total): 24 92 F1 + Codes of length 14 bits (004 total): 16 34 53 82 + Codes of length 15 bits (003 total): 25 83 C2 + Codes of length 16 bits (000 total): + Total number of codes: 046 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00001F12 + Huffman table length = 26 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 007 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00001F2E + Huffman table length = 45 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (004 total): 04 12 21 31 + Codes of length 06 bits (001 total): 41 + Codes of length 07 bits (004 total): 13 22 51 61 + Codes of length 08 bits (002 total): 32 71 + Codes of length 09 bits (002 total): 05 14 + Codes of length 10 bits (002 total): 23 91 + Codes of length 11 bits (001 total): F0 + Codes of length 12 bits (005 total): 33 42 81 A1 B1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 026 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001F5D + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00001F6B + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00007FFA.0 + + Compression stats: + Compression Ratio: 20.97:1 + Bits per pixel: 1.14:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 509 ( 18%) + # codes of length 03 bits: 1910 ( 69%) + # codes of length 04 bits: 249 ( 9%) + # codes of length 05 bits: 87 ( 3%) + # codes of length 06 bits: 5 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 905 ( 66%) + # codes of length 03 bits: 213 ( 15%) + # codes of length 04 bits: 169 ( 12%) + # codes of length 05 bits: 84 ( 6%) + # codes of length 06 bits: 9 ( 1%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 14518 ( 48%) + # codes of length 03 bits: 2881 ( 10%) + # codes of length 04 bits: 6591 ( 22%) + # codes of length 05 bits: 2038 ( 7%) + # codes of length 06 bits: 2356 ( 8%) + # codes of length 07 bits: 926 ( 3%) + # codes of length 08 bits: 484 ( 2%) + # codes of length 09 bits: 220 ( 1%) + # codes of length 10 bits: 149 ( 0%) + # codes of length 11 bits: 76 ( 0%) + # codes of length 12 bits: 27 ( 0%) + # codes of length 13 bits: 14 ( 0%) + # codes of length 14 bits: 8 ( 0%) + # codes of length 15 bits: 3 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2784 ( 53%) + # codes of length 03 bits: 1230 ( 24%) + # codes of length 04 bits: 370 ( 7%) + # codes of length 05 bits: 582 ( 11%) + # codes of length 06 bits: 94 ( 2%) + # codes of length 07 bits: 121 ( 2%) + # codes of length 08 bits: 26 ( 0%) + # codes of length 09 bits: 14 ( 0%) + # codes of length 10 bits: 6 ( 0%) + # codes of length 11 bits: 2 ( 0%) + # codes of length 12 bits: 5 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[122] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1008, 9, 27] RGB=[255,251,255] @ MCU[ 15, 13] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00007FF9.7 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00007FFA + + +*** Embedded JPEG Thumbnail *** + Offset: 0x00000812 + Length: 0x00001548 (5448) + + * Embedded Thumb Marker: SOI + + * Embedded Thumb Marker: DQT + Length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance, typically) + DQT, Row #0: 9 6 5 9 13 22 29 35 + DQT, Row #1: 6 6 8 11 15 33 34 30 + DQT, Row #2: 8 7 9 13 22 33 39 31 + DQT, Row #3: 8 9 12 16 28 49 45 34 + DQT, Row #4: 10 12 21 32 39 61 58 42 + DQT, Row #5: 13 19 31 36 45 58 63 51 + DQT, Row #6: 28 36 44 49 58 68 66 55 + DQT, Row #7: 41 52 54 55 62 56 57 54 + ---- + Precision=8 bits + Destination ID=1 (Chrominance, typically) + DQT, Row #0: 9 9 12 20 15 26 79 79 + DQT, Row #1: 9 10 12 10 26 26 79 79 + DQT, Row #2: 12 12 10 10 26 79 79 79 + DQT, Row #3: 20 10 10 26 79 79 79 79 + DQT, Row #4: 15 26 26 79 79 79 79 79 + DQT, Row #5: 26 26 79 79 79 79 79 79 + DQT, Row #6: 79 79 79 79 79 79 79 79 + DQT, Row #7: 79 79 79 79 79 79 79 79 + + * Embedded Thumb Marker: SOF + Frame header length = 17 + Precision = 8 + Number of Lines = 120 + Samples per Line = 160 + Image Size = 160 x 120 + + * Embedded Thumb Marker: DHT + Length = 418 + + * Embedded Thumb Marker: SOS + Skipping scan data + Skipped 4869 bytes + + * Embedded Thumb Marker: EOI + + * Embedded Thumb Signature: 01D91E583DD0037108266E42ED3A262C + +*** Searching Compression Signatures *** + + Signature: 0182408A81A4ABF04D4A34A8A5E98C58 + Signature (Rotated): 012D821C6AB210E2A753BE053B8F55D0 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: OK [Canon] [Canon PowerShot S40] + EXIF Makernotes: OK + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[SONY ] [CYBERSHOT U ] [ ] Yes + SW :[Adobe Photoshop 7.0 ] [Save As 07 ] + SW :[Apple Quicktime ] [0466-0467 ] + SW :[Digital Photo Professiona] [05 ] + SW :[IJG Library ] [075 ] + SW :[MS Paint ] [ ] + SW :[MS Visio ] [ ] + SW :[ZoomBrowser EX ] [low ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [075 ] + SW :[IrfanView ] [075 ] + SW :[idImager ] [075 ] + SW :[FastStone Image Viewer ] [075 ] + SW :[NeatImage ] [075 ] + SW :[Paint.NET ] [075 ] + SW :[Photomatix ] [075 ] + SW :[XnView ] [075 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 4 - Uncertain if processed or original + While the EXIF fields indicate original, no compression signatures + in the current database were found matching this make/model + + Appears to be new signature for known camera. + If the camera/software doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/gamma_dalai_lama_gray.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/gamma_dalai_lama_gray.jpg.txt new file mode 100644 index 0000000000..a5adb0247c --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/gamma_dalai_lama_gray.jpg.txt @@ -0,0 +1,339 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\gamma_dalai_lama_gray.jpg] + Filesize: [84887] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: COM (Comment) (xFFFE) *** + OFFSET: 0x00000014 + Comment length = 46 + Comment= Scaled 1:2 this image wrongly becomes gray. + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000044 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 1 1 1 + DQT, Row #4: 1 1 1 1 1 1 1 1 + DQT, Row #5: 1 1 1 1 1 1 1 1 + DQT, Row #6: 1 1 1 1 1 1 1 1 + DQT, Row #7: 1 1 1 1 1 1 1 1 + Approx quality factor = 100.00 (scaling=2.99 variance=6.13) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000089 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 1 1 1 + DQT, Row #4: 1 1 1 1 1 1 1 1 + DQT, Row #5: 1 1 1 1 1 1 1 1 + DQT, Row #6: 1 1 1 1 1 1 1 1 + DQT, Row #7: 1 1 1 1 1 1 1 1 + Approx quality factor = 100.00 (scaling=1.54 variance=1.58) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x000000CE + Frame header length = 17 + Precision = 8 + Number of Lines = 222 + Samples per Line = 258 + Image Size = 258 x 222 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000E1 + Huffman table length = 25 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (003 total): 01 02 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 006 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000FC + Huffman table length = 111 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (002 total): 04 11 + Codes of length 05 bits (002 total): 05 21 + Codes of length 06 bits (007 total): 00 06 12 13 14 31 41 + Codes of length 07 bits (003 total): 22 51 61 + Codes of length 08 bits (007 total): 07 15 16 32 42 71 81 + Codes of length 09 bits (005 total): 08 23 52 62 91 + Codes of length 10 bits (008 total): 33 43 44 72 A1 A2 B1 E3 + Codes of length 11 bits (010 total): 17 24 53 54 55 66 82 92 95 C1 + Codes of length 12 bits (009 total): 18 25 28 34 45 56 63 64 65 + Codes of length 13 bits (014 total): 26 27 46 73 76 85 93 96 A3 A5 A6 C3 C7 D7 + Codes of length 14 bits (010 total): 83 86 B2 B3 B8 C6 D3 D6 E8 F0 + Codes of length 15 bits (011 total): 36 37 48 74 75 84 94 A8 B4 B6 D1 + Codes of length 16 bits (001 total): D2 + Total number of codes: 092 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000016D + Huffman table length = 27 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (001 total): 06 + Codes of length 08 bits (001 total): 07 + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000018A + Huffman table length = 121 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 02 03 04 + Codes of length 04 bits (002 total): 05 11 + Codes of length 05 bits (002 total): 06 21 + Codes of length 06 bits (005 total): 07 08 12 13 31 + Codes of length 07 bits (009 total): 00 09 14 16 17 22 32 41 51 + Codes of length 08 bits (005 total): 0A 15 23 42 61 + Codes of length 09 bits (005 total): 18 24 33 52 71 + Codes of length 10 bits (002 total): 62 81 + Codes of length 11 bits (007 total): 19 34 43 53 72 82 91 + Codes of length 12 bits (007 total): 25 44 54 56 63 A1 A2 + Codes of length 13 bits (014 total): 1A 26 27 28 46 47 55 57 64 73 97 B1 E3 E6 + Codes of length 14 bits (007 total): 35 45 48 58 92 A4 C1 + Codes of length 15 bits (002 total): D8 29 + Codes of length 16 bits (031 total): 67 74 83 85 93 94 B2 36 68 87 88 98 D6 F0 37 39 + 65 66 75 78 84 96 A3 A6 A8 C3 C9 D1 D3 D9 DA + Total number of codes: 102 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000205 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00000213 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00014B95.0 + + Compression stats: + Compression Ratio: 2.04:1 + Bits per pixel: 11.78:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 893 ( 97%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 23 ( 2%) + # codes of length 04 bits: 4 ( 0%) + # codes of length 05 bits: 4 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 1728 ( 94%) + # codes of length 02 bits: 46 ( 2%) + # codes of length 03 bits: 30 ( 2%) + # codes of length 04 bits: 18 ( 1%) + # codes of length 05 bits: 14 ( 1%) + # codes of length 06 bits: 6 ( 0%) + # codes of length 07 bits: 4 ( 0%) + # codes of length 08 bits: 2 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 14381 ( 45%) + # codes of length 03 bits: 3819 ( 12%) + # codes of length 04 bits: 4489 ( 14%) + # codes of length 05 bits: 2199 ( 7%) + # codes of length 06 bits: 3836 ( 12%) + # codes of length 07 bits: 911 ( 3%) + # codes of length 08 bits: 1089 ( 3%) + # codes of length 09 bits: 398 ( 1%) + # codes of length 10 bits: 294 ( 1%) + # codes of length 11 bits: 190 ( 1%) + # codes of length 12 bits: 84 ( 0%) + # codes of length 13 bits: 75 ( 0%) + # codes of length 14 bits: 21 ( 0%) + # codes of length 15 bits: 11 ( 0%) + # codes of length 16 bits: 1 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 17100 ( 23%) + # codes of length 03 bits: 31709 ( 42%) + # codes of length 04 bits: 7638 ( 10%) + # codes of length 05 bits: 4203 ( 6%) + # codes of length 06 bits: 6465 ( 9%) + # codes of length 07 bits: 5462 ( 7%) + # codes of length 08 bits: 1472 ( 2%) + # codes of length 09 bits: 804 ( 1%) + # codes of length 10 bits: 206 ( 0%) + # codes of length 11 bits: 296 ( 0%) + # codes of length 12 bits: 156 ( 0%) + # codes of length 13 bits: 164 ( 0%) + # codes of length 14 bits: 47 ( 0%) + # codes of length 15 bits: 7 ( 0%) + # codes of length 16 bits: 55 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[125] (range: 0..255) + + Brightest Pixel Search: + YCC=[ -8, 0, 0] RGB=[127,127,127] @ MCU[ 0, 0] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00014B94.4 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00014B95 + + +*** Searching Compression Signatures *** + + Signature: 01BBB1709AC9C1F89220D955A31A8F34 + Signature (Rotated): 01BBB1709AC9C1F89220D955A31A8F34 + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[CASIO COMPUTER CO.,LTD ] [EX-Z750 ] [ ] No + CAM:[CASIO COMPUTER CO.,LTD. ] [EX-Z1000 ] [ ] No + CAM:[PENTAX ] [PENTAX Optio S5i ] [ ] No + CAM:[SIGMA ] [SIGMA SD9 ] [ ] No + SW :[ACDSee ] [100 ] + SW :[Apple ImageIO.framework ] [100 (Best) ] + SW :[Digital Photo Professiona] [10 ] + SW :[IJG Library ] [100 ] + SW :[MS Office Pic Mgr ] [ ] + SW :[Nikon Scan ] [Excellent Qualit] + SW :[Picasa ] [100 (Maximum) ] + SW :[ZoomBrowser EX ] [highest ] + SW :[EOS Viewer Utility ] [ ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [100 ] + SW :[IrfanView ] [100 ] + SW :[idImager ] [100 ] + SW :[FastStone Image Viewer ] [100 ] + SW :[NeatImage ] [100 ] + SW :[Paint.NET ] [100 ] + SW :[Photomatix ] [100 ] + SW :[XnView ] [100 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg400jfif.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg400jfif.jpg.txt new file mode 100644 index 0000000000..b686b3ce39 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg400jfif.jpg.txt @@ -0,0 +1,211 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\jpeg400jfif.jpg] + Filesize: [45066] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.2] + density = 300 x 300 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 9 11 12 16 + DQT, Row #1: 4 5 5 6 8 10 12 12 + DQT, Row #2: 4 5 5 6 10 12 12 12 + DQT, Row #3: 6 6 6 11 12 12 12 12 + DQT, Row #4: 9 8 10 12 12 12 12 12 + DQT, Row #5: 11 10 12 12 12 12 12 12 + DQT, Row #6: 12 12 12 12 12 12 12 12 + DQT, Row #7: 16 12 12 12 12 12 12 12 + Approx quality factor = 88.28 (scaling=23.43 variance=111.68) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00000059 + Frame header length = 11 + Precision = 8 + Number of Lines = 800 + Samples per Line = 600 + Image Size = 600 x 800 + Raw Image Orientation = Portrait + Number of Img components = 1 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x00000066 + Length = 4 + interval = 75 + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000006C + Huffman table length = 210 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (007 total): 04 05 03 02 06 01 00 + Codes of length 04 bits (001 total): 07 + Codes of length 05 bits (001 total): 08 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (001 total): 0A + Codes of length 08 bits (001 total): 0B + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 11 04 00 + Codes of length 05 bits (003 total): 05 21 12 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 51 06 13 61 + Codes of length 08 bits (002 total): 22 71 + Codes of length 09 bits (006 total): 81 14 32 91 A1 07 + Codes of length 10 bits (007 total): 15 B1 42 23 C1 52 D1 + Codes of length 11 bits (003 total): E1 33 16 + Codes of length 12 bits (004 total): 62 F0 24 72 + Codes of length 13 bits (002 total): 82 F1 + Codes of length 14 bits (006 total): 25 43 34 53 92 A2 + Codes of length 15 bits (002 total): B2 63 + Codes of length 16 bits (115 total): 73 C2 35 44 27 93 A3 B3 36 17 54 64 74 C3 D2 E2 + 08 26 83 09 0A 18 19 84 94 45 46 A4 B4 56 D3 55 + 28 1A F2 E3 F3 C4 D4 E4 F4 65 75 85 95 A5 B5 C5 + D5 E5 F5 66 76 86 96 A6 B6 C6 D6 E6 F6 37 47 57 + 67 77 87 97 A7 B7 C7 D7 E7 F7 38 48 58 68 78 88 + 98 A8 B8 C8 D8 E8 F8 29 39 49 59 69 79 89 99 A9 + B9 C9 D9 E9 F9 2A 3A 4A 5A 6A 7A 8A 9A AA BA CA + DA EA FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000140 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x0000014A + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0000B008.0 + + Compression stats: + Compression Ratio: 10.73:1 + Bits per pixel: 0.75:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 7215 ( 96%) + # codes of length 04 bits: 146 ( 2%) + # codes of length 05 bits: 139 ( 2%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 26194 ( 42%) + # codes of length 03 bits: 2772 ( 4%) + # codes of length 04 bits: 16626 ( 27%) + # codes of length 05 bits: 5914 ( 9%) + # codes of length 06 bits: 4996 ( 8%) + # codes of length 07 bits: 2599 ( 4%) + # codes of length 08 bits: 988 ( 2%) + # codes of length 09 bits: 1360 ( 2%) + # codes of length 10 bits: 617 ( 1%) + # codes of length 11 bits: 60 ( 0%) + # codes of length 12 bits: 152 ( 0%) + # codes of length 13 bits: 60 ( 0%) + # codes of length 14 bits: 30 ( 0%) + # codes of length 15 bits: 5 ( 0%) + # codes of length 16 bits: 28 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[ 58] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 894, 0, 0] RGB=[239,239,239] @ MCU[ 35, 23] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 99 + Next position in scan buffer: Offset 0x0000B007.2 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000B008 + + +*** Searching Compression Signatures *** + + Signature: 01BE82BEB1019CB30EB122273E78E87C + Signature (Rotated): 01BE82BEB1019CB30EB122273E78E87C + File Offset: 0 bytes + Chroma subsampling: Gray + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg420exif.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg420exif.jpg.txt new file mode 100644 index 0000000000..babe797d6a --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg420exif.jpg.txt @@ -0,0 +1,412 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\jpeg420exif.jpg] + Filesize: [768608] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000002 + Length = 8817 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000014 + Dir Length = 0x0008 + [Make ] = "Hewlett-Packard Company" + [Model ] = "HP PhotoSmart 715" + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [YCbCrPositioning ] = Centered + [ExifOffset ] = @ 0x006E + Offset to Next IFD = 0x0000018E + + EXIF IFD1 @ Absolute 0x0000019A + Dir Length = 0x0007 + [Compression ] = JPEG + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x0C07 = @ 0x0C13 + [JpegIFByteCount ] = 0x[00001658] / 5720 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x0000007A + Dir Length = 0x0015 + [ExposureTime ] = 48/10000 s + [FNumber ] = F8.2 + [ISOSpeedRatings ] = 100 + [ExifVersion ] = 02.10 + [DateTimeOriginal ] = "2001:10:02 14:57:31" + [DateTimeDigitized ] = "2001:10:02 14:57:31" + [ComponentsConfiguration ] = [Y Cb Cr .] + [CompressedBitsPerPixel ] = 20/10 + [ExposureBiasValue ] = 0.00 eV + [MaxApertureValue ] = 20/10 + [SubjectDistance ] = 5043/1000 + [MeteringMode ] = CenterWeightedAverage + [LightSource ] = unknown + [Flash ] = Flash did not fire + [FocalLength ] = 7 mm + [MakerNote ] = @ 0x0282 + [FlashPixVersion ] = 01.00 + [ColorSpace ] = sRGB + [ExifImageWidth ] = 2048 + [ExifImageHeight ] = 1536 + [ExifInteroperabilityOffset ] = @ 0x0170 + + EXIF MakerIFD @ Absolute 0x0000028E + Makernote decode option not enabled. + + EXIF InteropIFD @ Absolute 0x0000017C + Dir Length = 0x0002 + [InteroperabilityIndex ] = "R98" + [InteroperabilityVersion ] = 01.00 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00002275 + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 5 9 11 14 + DQT, Row #1: 3 3 3 4 5 12 13 12 + DQT, Row #2: 3 3 3 5 9 12 15 12 + DQT, Row #3: 3 3 5 6 11 19 18 13 + DQT, Row #4: 3 5 7 12 15 24 23 17 + DQT, Row #5: 5 7 12 14 18 23 25 21 + DQT, Row #6: 11 14 17 19 23 27 27 22 + DQT, Row #7: 16 21 21 22 25 22 23 22 + Approx quality factor = 89.24 (scaling=21.52 variance=2.21) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 3 3 5 10 22 22 22 22 + DQT, Row #1: 3 5 5 14 22 22 22 22 + DQT, Row #2: 5 5 11 22 22 22 22 22 + DQT, Row #3: 10 14 22 22 22 22 22 22 + DQT, Row #4: 22 22 22 22 22 22 22 22 + DQT, Row #5: 22 22 22 22 22 22 22 22 + DQT, Row #6: 22 22 22 22 22 22 22 22 + DQT, Row #7: 22 22 22 22 22 22 22 22 + Approx quality factor = 89.12 (scaling=21.76 variance=1.62) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000022FB + Huffman table length = 418 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000249F + Frame header length = 17 + Precision = 8 + Number of Lines = 1536 + Samples per Line = 2048 + Image Size = 2048 x 1536 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000024B2 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000024C0 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x000BBA5E.0 + + Compression stats: + Compression Ratio: 12.43:1 + Bits per pixel: 1.93:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 4275 ( 9%) + # codes of length 03 bits: 32688 ( 67%) + # codes of length 04 bits: 5786 ( 12%) + # codes of length 05 bits: 3984 ( 8%) + # codes of length 06 bits: 2042 ( 4%) + # codes of length 07 bits: 377 ( 1%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 16194 ( 66%) + # codes of length 03 bits: 3495 ( 14%) + # codes of length 04 bits: 2416 ( 10%) + # codes of length 05 bits: 1460 ( 6%) + # codes of length 06 bits: 736 ( 3%) + # codes of length 07 bits: 261 ( 1%) + # codes of length 08 bits: 14 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 363342 ( 41%) + # codes of length 03 bits: 113855 ( 13%) + # codes of length 04 bits: 200569 ( 23%) + # codes of length 05 bits: 102577 ( 12%) + # codes of length 06 bits: 32874 ( 4%) + # codes of length 07 bits: 43593 ( 5%) + # codes of length 08 bits: 14054 ( 2%) + # codes of length 09 bits: 8847 ( 1%) + # codes of length 10 bits: 4365 ( 0%) + # codes of length 11 bits: 2009 ( 0%) + # codes of length 12 bits: 770 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 17 ( 0%) + # codes of length 16 bits: 780 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 60258 ( 49%) + # codes of length 03 bits: 17570 ( 14%) + # codes of length 04 bits: 20881 ( 17%) + # codes of length 05 bits: 14001 ( 11%) + # codes of length 06 bits: 6443 ( 5%) + # codes of length 07 bits: 842 ( 1%) + # codes of length 08 bits: 1737 ( 1%) + # codes of length 09 bits: 387 ( 0%) + # codes of length 10 bits: 169 ( 0%) + # codes of length 11 bits: 93 ( 0%) + # codes of length 12 bits: 31 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 2 ( 0%) + # codes of length 15 bits: 5 ( 0%) + # codes of length 16 bits: 1 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[108] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 996, 0, -33] RGB=[244,255,252] @ MCU[ 32, 59] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x000BBA5D.5 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x000BBA5E + + +*** Embedded JPEG Thumbnail *** + Offset: 0x00000C13 + Length: 0x00001658 (5720) + + * Embedded Thumb Marker: SOI + + * Embedded Thumb Marker: DQT + Length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance, typically) + DQT, Row #0: 10 6 6 10 14 26 32 40 + DQT, Row #1: 8 8 8 12 16 36 38 36 + DQT, Row #2: 8 8 10 14 26 36 44 36 + DQT, Row #3: 8 10 14 18 32 56 52 40 + DQT, Row #4: 10 14 22 36 44 70 66 50 + DQT, Row #5: 14 22 36 42 52 68 74 60 + DQT, Row #6: 32 42 50 56 66 78 78 64 + DQT, Row #7: 46 60 62 64 74 64 66 64 + ---- + Precision=8 bits + Destination ID=1 (Chrominance, typically) + DQT, Row #0: 10 10 14 30 64 64 64 64 + DQT, Row #1: 10 14 16 42 64 64 64 64 + DQT, Row #2: 14 16 36 64 64 64 64 64 + DQT, Row #3: 30 42 64 64 64 64 64 64 + DQT, Row #4: 64 64 64 64 64 64 64 64 + DQT, Row #5: 64 64 64 64 64 64 64 64 + DQT, Row #6: 64 64 64 64 64 64 64 64 + DQT, Row #7: 64 64 64 64 64 64 64 64 + + * Embedded Thumb Marker: DHT + Length = 418 + + * Embedded Thumb Marker: SOF + Frame header length = 17 + Precision = 8 + Number of Lines = 120 + Samples per Line = 160 + Image Size = 160 x 120 + + * Embedded Thumb Marker: SOS + Skipping scan data + Skipped 5141 bytes + + * Embedded Thumb Marker: EOI + + * Embedded Thumb Signature: 0158E595F22440126FB766B33F56B158 + +*** Searching Compression Signatures *** + + Signature: 010A5B03EB73D6AF719B39FCC8C3AE25 + Signature (Rotated): 011326BE69D2A27FCF4DBCC33DEB07A2 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: OK [Hewlett-Packard Company] [HP PhotoSmart 715] + EXIF Makernotes: OK + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 4 - Uncertain if processed or original + While the EXIF fields indicate original, no compression signatures + in the current database were found matching this make/model + + Appears to be new signature for known camera. + If the camera/software doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg420small.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg420small.jpg.txt new file mode 100644 index 0000000000..c001d7297a --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg420small.jpg.txt @@ -0,0 +1,330 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\jpeg420small.jpg] + Filesize: [5276] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 96 x 96 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 5 3 3 5 7 12 15 18 + DQT, Row #1: 4 4 4 6 8 17 18 17 + DQT, Row #2: 4 4 5 7 12 17 21 17 + DQT, Row #3: 4 5 7 9 15 26 24 19 + DQT, Row #4: 5 7 11 17 20 33 31 23 + DQT, Row #5: 7 11 17 19 24 31 34 28 + DQT, Row #6: 15 19 23 26 31 36 36 30 + DQT, Row #7: 22 28 29 29 34 30 31 30 + Approx quality factor = 84.93 (scaling=30.13 variance=1.05) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 5 5 7 14 30 30 30 30 + DQT, Row #1: 5 6 8 20 30 30 30 30 + DQT, Row #2: 7 8 17 30 30 30 30 30 + DQT, Row #3: 14 20 30 30 30 30 30 30 + DQT, Row #4: 30 30 30 30 30 30 30 30 + DQT, Row #5: 30 30 30 30 30 30 30 30 + DQT, Row #6: 30 30 30 30 30 30 30 30 + DQT, Row #7: 30 30 30 30 30 30 30 30 + Approx quality factor = 84.93 (scaling=30.15 variance=0.29) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 100 + Samples per Line = 200 + Image Size = 200 x 100 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 28 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 04 + Codes of length 03 bits (005 total): 00 02 03 05 07 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 01 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000CF + Huffman table length = 66 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 11 21 + Codes of length 05 bits (002 total): 04 12 + Codes of length 06 bits (004 total): 05 06 31 41 + Codes of length 07 bits (004 total): 07 13 22 51 + Codes of length 08 bits (002 total): 32 61 + Codes of length 09 bits (005 total): 71 72 B1 D1 D2 + Codes of length 10 bits (007 total): 14 23 33 62 81 91 A1 + Codes of length 11 bits (010 total): 15 16 24 25 34 42 44 82 92 A2 + Codes of length 12 bits (007 total): 26 52 53 54 64 94 C2 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 047 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000113 + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 06 07 + Codes of length 03 bits (002 total): 04 05 + Codes of length 04 bits (003 total): 00 03 08 + Codes of length 05 bits (001 total): 01 + Codes of length 06 bits (001 total): 02 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000131 + Huffman table length = 63 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 02 + Codes of length 04 bits (002 total): 03 04 + Codes of length 05 bits (004 total): 05 06 11 21 + Codes of length 06 bits (007 total): 07 12 34 51 61 72 B1 + Codes of length 07 bits (014 total): 13 15 16 17 31 32 33 35 41 53 71 91 92 D1 + Codes of length 08 bits (004 total): 22 62 C1 E1 + Codes of length 09 bits (006 total): 14 52 54 81 82 B2 + Codes of length 10 bits (003 total): 36 42 C2 + Codes of length 11 bits (001 total): F0 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 044 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000172 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00000180 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0000149A.0 + + Compression stats: + Compression Ratio: 12.27:1 + Bits per pixel: 1.96:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 69 ( 19%) + # codes of length 03 bits: 232 ( 64%) + # codes of length 04 bits: 34 ( 9%) + # codes of length 05 bits: 19 ( 5%) + # codes of length 06 bits: 10 ( 3%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 76 ( 42%) + # codes of length 03 bits: 60 ( 33%) + # codes of length 04 bits: 36 ( 20%) + # codes of length 05 bits: 5 ( 3%) + # codes of length 06 bits: 5 ( 3%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2698 ( 51%) + # codes of length 03 bits: 506 ( 10%) + # codes of length 04 bits: 1064 ( 20%) + # codes of length 05 bits: 373 ( 7%) + # codes of length 06 bits: 334 ( 6%) + # codes of length 07 bits: 133 ( 3%) + # codes of length 08 bits: 37 ( 1%) + # codes of length 09 bits: 43 ( 1%) + # codes of length 10 bits: 33 ( 1%) + # codes of length 11 bits: 26 ( 0%) + # codes of length 12 bits: 7 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 276 ( 20%) + # codes of length 03 bits: 340 ( 25%) + # codes of length 04 bits: 214 ( 15%) + # codes of length 05 bits: 190 ( 14%) + # codes of length 06 bits: 141 ( 10%) + # codes of length 07 bits: 170 ( 12%) + # codes of length 08 bits: 29 ( 2%) + # codes of length 09 bits: 17 ( 1%) + # codes of length 10 bits: 6 ( 0%) + # codes of length 11 bits: 1 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[ 86] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 250, -405, 230] RGB=[198,156, 68] @ MCU[ 0, 6] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00001499.3 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000149A + + +*** Searching Compression Signatures *** + + Signature: 0155D875C95B74D0F3C5835A62516F48 + Signature (Rotated): 01D38A25358EB7649A254E19F1D46600 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[Nokia ] [N73 ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 8100 ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + SW :[IJG Library ] [085 ] + SW :[Picasa ] [085 (Normal) ] + SW :[ZoomBrowser EX ] [medium ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [085 ] + SW :[IrfanView ] [085 ] + SW :[idImager ] [085 ] + SW :[FastStone Image Viewer ] [085 ] + SW :[NeatImage ] [085 ] + SW :[Paint.NET ] [085 ] + SW :[Photomatix ] [085 ] + SW :[XnView ] [085 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg444.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg444.jpg.txt new file mode 100644 index 0000000000..06a1ee4263 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg444.jpg.txt @@ -0,0 +1,405 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\jpeg444.jpg] + Filesize: [5667] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.0] + density = 300 x 300 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 68 + Identifier = [This is an unknown APP marker. Compliant decoders must ignore it.] +Identifier [This is an unknown APP marker. Compliant decoders must ignore it.] not supported. Skipping remainder. + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0000005A + Length = 68 + Identifier = [This is an unknown APP marker. Compliant decoders must ignore it.] + Not supported. Skipping remainder. + +*** Marker: APP3 (xFFE3) *** + OFFSET: 0x000000A0 + Length = 68 + +*** Marker: APP4 (xFFE4) *** + OFFSET: 0x000000E6 + Length = 68 + +*** Marker: APP5 (xFFE5) *** + OFFSET: 0x0000012C + Length = 68 + +*** Marker: APP6 (xFFE6) *** + OFFSET: 0x00000172 + Length = 68 + +*** Marker: APP7 (xFFE7) *** + OFFSET: 0x000001B8 + Length = 68 + +*** Marker: APP8 (xFFE8) *** + OFFSET: 0x000001FE + Length = 68 + +*** Marker: APP9 (xFFE9) *** + OFFSET: 0x00000244 + Length = 68 + +*** Marker: APP10 (xFFEA) *** + OFFSET: 0x0000028A + Length = 68 + +*** Marker: APP11 (xFFEB) *** + OFFSET: 0x000002D0 + Length = 68 + +*** Marker: APP12 (xFFEC) *** + OFFSET: 0x00000316 + Length = 68 + Identifier = [This is an unknown APP marker. Compliant decoders must ignore it.] + Not Photoshop DUCKY. Skipping remainder. + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x0000035C + Length = 68 + Identifier = [This is an unknown APP marker. Compliant decoders must ignore it.] + Not Photoshop. Skipping remainder. + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x000003A2 + Length = 68 + DCTEncodeVersion = 26995 + APP14Flags0 = 8289 + APP14Flags1 = 28192 + ColorTransform = 117 [???] + +*** Marker: APP15 (xFFEF) *** + OFFSET: 0x000003E8 + Length = 68 + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000042E + Frame header length = 17 + Precision = 8 + Number of Lines = 256 + Samples per Line = 256 + Image Size = 256 x 256 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x02 (Chrom: Cr) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000441 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 8 6 5 8 12 20 26 31 + DQT, Row #1: 6 6 7 10 13 29 30 28 + DQT, Row #2: 7 7 8 12 20 29 35 28 + DQT, Row #3: 7 9 11 15 26 44 40 31 + DQT, Row #4: 9 11 19 28 34 55 52 39 + DQT, Row #5: 12 18 28 32 41 52 57 46 + DQT, Row #6: 25 32 39 44 52 61 60 51 + DQT, Row #7: 36 46 48 49 56 50 52 50 + Approx quality factor = 74.75 (scaling=50.51 variance=0.81) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000486 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + Approx quality factor = 74.74 (scaling=50.52 variance=0.19) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000004CB + Table length = 67 + ---- + Precision=8 bits + Destination ID=2 (Chrominance) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + Approx quality factor = 74.74 (scaling=50.52 variance=0.19) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000510 + Huffman table length = 418 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000006B4 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000006C2 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00001620.0 + + Compression stats: + Compression Ratio: 49.99:1 + Bits per pixel: 0.48:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 992 ( 97%) + # codes of length 03 bits: 31 ( 3%) + # codes of length 04 bits: 0 ( 0%) + # codes of length 05 bits: 1 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 1023 ( 50%) + # codes of length 03 bits: 864 ( 42%) + # codes of length 04 bits: 128 ( 6%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 2 ( 0%) + # codes of length 08 bits: 31 ( 2%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 0 ( 0%) + # codes of length 04 bits: 1024 ( 50%) + # codes of length 05 bits: 1024 ( 50%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2048 ( 67%) + # codes of length 03 bits: 1024 ( 33%) + # codes of length 04 bits: 0 ( 0%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[126] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 984,-1026, -999] RGB=[ 75,255, 24] @ MCU[ 0, 31] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x0000161F.6 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00001620 + + +*** Searching Compression Signatures *** + + Signature: 019DC7724B5425C464D28F2CF78F707E + Signature (Rotated): 016C4383FFABE35F063D8FCB331942C0 + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[NIKON ] [E4800 ] [NORMAL ] No + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + + +*** Additional Info *** +NOTE: Data exists after EOF, range: 0x00001622-0x00001623 (1 bytes) diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/ratio-1x1.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/ratio-1x1.jpg.txt new file mode 100644 index 0000000000..b2ae24c469 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/ratio-1x1.jpg.txt @@ -0,0 +1,338 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\ratio-1x1.jpg] + Filesize: [34674] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 4 6 8 10 + DQT, Row #1: 2 2 2 3 4 9 10 9 + DQT, Row #2: 2 2 3 4 6 9 11 9 + DQT, Row #3: 2 3 4 5 8 14 13 10 + DQT, Row #4: 3 4 6 9 11 17 16 12 + DQT, Row #5: 4 6 9 10 13 17 18 15 + DQT, Row #6: 8 10 12 14 16 19 19 16 + DQT, Row #7: 12 15 15 16 18 16 16 16 + Approx quality factor = 91.86 (scaling=16.28 variance=1.13) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 3 3 4 8 16 16 16 16 + DQT, Row #1: 3 3 4 11 16 16 16 16 + DQT, Row #2: 4 4 9 16 16 16 16 16 + DQT, Row #3: 8 11 16 16 16 16 16 16 + DQT, Row #4: 16 16 16 16 16 16 16 16 + DQT, Row #5: 16 16 16 16 16 16 16 16 + DQT, Row #6: 16 16 16 16 16 16 16 16 + DQT, Row #7: 16 16 16 16 16 16 16 16 + Approx quality factor = 91.90 (scaling=16.20 variance=0.15) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 769 + Samples per Line = 1900 + Image Size = 1900 x 769 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 29 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 07 08 + Codes of length 04 bits (002 total): 06 09 + Codes of length 05 bits (002 total): 04 05 + Codes of length 06 bits (003 total): 01 02 03 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 010 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000D0 + Huffman table length = 78 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (001 total): 01 + Codes of length 04 bits (003 total): 02 03 04 + Codes of length 05 bits (003 total): 05 06 11 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (005 total): 08 12 21 31 41 + Codes of length 08 bits (005 total): 13 14 22 51 61 + Codes of length 09 bits (003 total): 15 32 71 + Codes of length 10 bits (009 total): 09 16 23 52 62 81 91 92 A1 + Codes of length 11 bits (005 total): 17 33 42 72 82 + Codes of length 12 bits (005 total): 24 43 54 93 B3 + Codes of length 13 bits (006 total): 63 73 83 A2 B2 C2 + Codes of length 14 bits (003 total): 25 44 A3 + Codes of length 15 bits (009 total): 34 35 36 37 64 76 B1 B4 C1 + Codes of length 16 bits (000 total): + Total number of codes: 059 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000120 + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (003 total): 05 06 07 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (000 total): + Codes of length 06 bits (003 total): 02 03 08 + Codes of length 07 bits (001 total): 01 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000013E + Huffman table length = 64 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (001 total): 01 + Codes of length 04 bits (002 total): 02 03 + Codes of length 05 bits (003 total): 04 05 11 + Codes of length 06 bits (005 total): 06 21 31 71 81 + Codes of length 07 bits (003 total): 41 51 91 + Codes of length 08 bits (010 total): 12 13 14 22 32 61 A1 B1 C1 D1 + Codes of length 09 bits (005 total): 15 33 42 E1 F0 + Codes of length 10 bits (003 total): 07 23 52 + Codes of length 11 bits (004 total): 43 62 72 82 + Codes of length 12 bits (002 total): 92 F1 + Codes of length 13 bits (001 total): B2 + Codes of length 14 bits (005 total): 16 A2 C2 D2 E2 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 045 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000180 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x0000018E + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00008770.0 + + Compression stats: + Compression Ratio: 127.89:1 + Bits per pixel: 0.19:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 22539 ( 97%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 379 ( 2%) + # codes of length 04 bits: 246 ( 1%) + # codes of length 05 bits: 91 ( 0%) + # codes of length 06 bits: 69 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 11012 ( 94%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 445 ( 4%) + # codes of length 04 bits: 105 ( 1%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 81 ( 1%) + # codes of length 07 bits: 19 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 23301 ( 56%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 4265 ( 10%) + # codes of length 04 bits: 7407 ( 18%) + # codes of length 05 bits: 3364 ( 8%) + # codes of length 06 bits: 767 ( 2%) + # codes of length 07 bits: 1399 ( 3%) + # codes of length 08 bits: 642 ( 2%) + # codes of length 09 bits: 201 ( 0%) + # codes of length 10 bits: 285 ( 1%) + # codes of length 11 bits: 99 ( 0%) + # codes of length 12 bits: 42 ( 0%) + # codes of length 13 bits: 30 ( 0%) + # codes of length 14 bits: 6 ( 0%) + # codes of length 15 bits: 9 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 11662 ( 60%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 1971 ( 10%) + # codes of length 04 bits: 1938 ( 10%) + # codes of length 05 bits: 1525 ( 8%) + # codes of length 06 bits: 1005 ( 5%) + # codes of length 07 bits: 339 ( 2%) + # codes of length 08 bits: 727 ( 4%) + # codes of length 09 bits: 148 ( 1%) + # codes of length 10 bits: 41 ( 0%) + # codes of length 11 bits: 23 ( 0%) + # codes of length 12 bits: 8 ( 0%) + # codes of length 13 bits: 2 ( 0%) + # codes of length 14 bits: 5 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[250] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1017, 0, 0] RGB=[255,255,255] @ MCU[ 0, 0] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x0000876F.5 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00008770 + + +*** Searching Compression Signatures *** + + Signature: 01557A9AE226A38386271DFE13D64298 + Signature (Rotated): 0167FCEDBA3A8E8CF822163DB3564762 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[Konica Minolta Camera, In] [DiMAGE Z2 ] [ ] No + CAM:[Minolta Co., Ltd. ] [DiMAGE F100 ] [ ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5000 ] [FINE ] No + CAM:[NIKON ] [E8700 ] [FINE ] No + CAM:[NIKON ] [E885 ] [FINE ] No + CAM:[OLYMPUS CORPORATION ] [C8080WZ ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-H2 ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-P200 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-W7 ] [ ] No + SW :[IJG Library ] [092 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [092 ] + SW :[IrfanView ] [092 ] + SW :[idImager ] [092 ] + SW :[FastStone Image Viewer ] [092 ] + SW :[NeatImage ] [092 ] + SW :[Paint.NET ] [092 ] + SW :[Photomatix ] [092 ] + SW :[XnView ] [092 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/testimgint.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/testimgint.jpg.txt new file mode 100644 index 0000000000..ac2b2f9adb --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/testimgint.jpg.txt @@ -0,0 +1,342 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\testimgint.jpg] + Filesize: [5756] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 8 6 5 8 12 20 26 31 + DQT, Row #1: 6 6 7 10 13 29 30 28 + DQT, Row #2: 7 7 8 12 20 29 35 28 + DQT, Row #3: 7 9 11 15 26 44 40 31 + DQT, Row #4: 9 11 19 28 34 55 52 39 + DQT, Row #5: 12 18 28 32 41 52 57 46 + DQT, Row #6: 25 32 39 44 52 61 60 51 + DQT, Row #7: 36 46 48 49 56 50 52 50 + Approx quality factor = 74.75 (scaling=50.51 variance=0.81) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + Approx quality factor = 74.74 (scaling=50.52 variance=0.19) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 149 + Samples per Line = 227 + Image Size = 227 x 149 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000D2 + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000189 + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000001AA + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000261 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x0000026F + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0000167A.0 + + Compression stats: + Compression Ratio: 19.78:1 + Bits per pixel: 1.21:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 86 ( 14%) + # codes of length 03 bits: 412 ( 69%) + # codes of length 04 bits: 65 ( 11%) + # codes of length 05 bits: 33 ( 6%) + # codes of length 06 bits: 4 ( 1%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 132 ( 44%) + # codes of length 03 bits: 70 ( 23%) + # codes of length 04 bits: 60 ( 20%) + # codes of length 05 bits: 26 ( 9%) + # codes of length 06 bits: 12 ( 4%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2692 ( 48%) + # codes of length 03 bits: 628 ( 11%) + # codes of length 04 bits: 1327 ( 23%) + # codes of length 05 bits: 471 ( 8%) + # codes of length 06 bits: 199 ( 4%) + # codes of length 07 bits: 170 ( 3%) + # codes of length 08 bits: 65 ( 1%) + # codes of length 09 bits: 58 ( 1%) + # codes of length 10 bits: 31 ( 1%) + # codes of length 11 bits: 15 ( 0%) + # codes of length 12 bits: 4 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 6 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 689 ( 46%) + # codes of length 03 bits: 244 ( 16%) + # codes of length 04 bits: 289 ( 19%) + # codes of length 05 bits: 158 ( 11%) + # codes of length 06 bits: 70 ( 5%) + # codes of length 07 bits: 5 ( 0%) + # codes of length 08 bits: 36 ( 2%) + # codes of length 09 bits: 5 ( 0%) + # codes of length 10 bits: 1 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[107] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1008, -9, 0] RGB=[254,254,250] @ MCU[ 4, 8] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00001679.6 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000167A + + +*** Searching Compression Signatures *** + + Signature: 0182408A81A4ABF04D4A34A8A5E98C58 + Signature (Rotated): 012D821C6AB210E2A753BE053B8F55D0 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[SONY ] [CYBERSHOT U ] [ ] Yes + SW :[Adobe Photoshop 7.0 ] [Save As 07 ] + SW :[Apple Quicktime ] [0466-0467 ] + SW :[Digital Photo Professiona] [05 ] + SW :[IJG Library ] [075 ] + SW :[MS Paint ] [ ] + SW :[MS Visio ] [ ] + SW :[ZoomBrowser EX ] [low ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [075 ] + SW :[IrfanView ] [075 ] + SW :[idImager ] [075 ] + SW :[FastStone Image Viewer ] [075 ] + SW :[NeatImage ] [075 ] + SW :[Paint.NET ] [075 ] + SW :[Photomatix ] [075 ] + SW :[XnView ] [075 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/testorig.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/testorig.jpg.txt new file mode 100644 index 0000000000..8e339260ba --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/testorig.jpg.txt @@ -0,0 +1,342 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\testorig.jpg] + Filesize: [5770] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 8 6 5 8 12 20 26 31 + DQT, Row #1: 6 6 7 10 13 29 30 28 + DQT, Row #2: 7 7 8 12 20 29 35 28 + DQT, Row #3: 7 9 11 15 26 44 40 31 + DQT, Row #4: 9 11 19 28 34 55 52 39 + DQT, Row #5: 12 18 28 32 41 52 57 46 + DQT, Row #6: 25 32 39 44 52 61 60 51 + DQT, Row #7: 36 46 48 49 56 50 52 50 + Approx quality factor = 74.75 (scaling=50.51 variance=0.81) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + Approx quality factor = 74.74 (scaling=50.52 variance=0.19) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 149 + Samples per Line = 227 + Image Size = 227 x 149 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000D2 + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000189 + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000001AA + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000261 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x0000026F + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00001688.0 + + Compression stats: + Compression Ratio: 19.73:1 + Bits per pixel: 1.22:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 88 ( 15%) + # codes of length 03 bits: 409 ( 68%) + # codes of length 04 bits: 66 ( 11%) + # codes of length 05 bits: 33 ( 6%) + # codes of length 06 bits: 4 ( 1%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 134 ( 45%) + # codes of length 03 bits: 68 ( 23%) + # codes of length 04 bits: 60 ( 20%) + # codes of length 05 bits: 26 ( 9%) + # codes of length 06 bits: 12 ( 4%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2706 ( 48%) + # codes of length 03 bits: 636 ( 11%) + # codes of length 04 bits: 1331 ( 23%) + # codes of length 05 bits: 473 ( 8%) + # codes of length 06 bits: 196 ( 3%) + # codes of length 07 bits: 169 ( 3%) + # codes of length 08 bits: 66 ( 1%) + # codes of length 09 bits: 60 ( 1%) + # codes of length 10 bits: 28 ( 0%) + # codes of length 11 bits: 14 ( 0%) + # codes of length 12 bits: 4 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 5 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 697 ( 46%) + # codes of length 03 bits: 243 ( 16%) + # codes of length 04 bits: 294 ( 19%) + # codes of length 05 bits: 164 ( 11%) + # codes of length 06 bits: 68 ( 4%) + # codes of length 07 bits: 5 ( 0%) + # codes of length 08 bits: 35 ( 2%) + # codes of length 09 bits: 4 ( 0%) + # codes of length 10 bits: 2 ( 0%) + # codes of length 11 bits: 1 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[107] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1008, -9, 0] RGB=[254,254,250] @ MCU[ 4, 8] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00001687.2 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00001688 + + +*** Searching Compression Signatures *** + + Signature: 0182408A81A4ABF04D4A34A8A5E98C58 + Signature (Rotated): 012D821C6AB210E2A753BE053B8F55D0 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[SONY ] [CYBERSHOT U ] [ ] Yes + SW :[Adobe Photoshop 7.0 ] [Save As 07 ] + SW :[Apple Quicktime ] [0466-0467 ] + SW :[Digital Photo Professiona] [05 ] + SW :[IJG Library ] [075 ] + SW :[MS Paint ] [ ] + SW :[MS Visio ] [ ] + SW :[ZoomBrowser EX ] [low ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [075 ] + SW :[IrfanView ] [075 ] + SW :[idImager ] [075 ] + SW :[FastStone Image Viewer ] [075 ] + SW :[NeatImage ] [075 ] + SW :[Paint.NET ] [075 ] + SW :[Photomatix ] [075 ] + SW :[XnView ] [075 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/turtle.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/turtle.jpg.txt new file mode 100644 index 0000000000..a8231b19e6 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/turtle.jpg.txt @@ -0,0 +1,367 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\turtle.jpg] + Filesize: [55126] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 28 x 28 DPcm (dots per cm) + thumbnail = 0 x 0 + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00000014 + Length = 3256 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 3240 bytes + Preferred CMM Type : 'appl' (0x6170706C) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 2012-05-11 16:46:50 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Apple Computer, Inc. ('APPL' (0x4150504C)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : '....' (0x00000000) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'appl' (0x6170706C) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000CCE + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 4 6 8 10 + DQT, Row #1: 2 2 2 3 4 9 10 9 + DQT, Row #2: 2 2 3 4 6 9 11 9 + DQT, Row #3: 2 3 4 5 8 14 13 10 + DQT, Row #4: 3 4 6 9 11 17 16 12 + DQT, Row #5: 4 6 9 10 13 17 18 15 + DQT, Row #6: 8 10 12 14 16 19 19 16 + DQT, Row #7: 12 15 15 16 18 16 16 16 + Approx quality factor = 91.86 (scaling=16.28 variance=1.13) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000D13 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 3 3 4 8 16 16 16 16 + DQT, Row #1: 3 3 4 11 16 16 16 16 + DQT, Row #2: 4 4 9 16 16 16 16 16 + DQT, Row #3: 8 11 16 16 16 16 16 16 + DQT, Row #4: 16 16 16 16 16 16 16 16 + DQT, Row #5: 16 16 16 16 16 16 16 16 + DQT, Row #6: 16 16 16 16 16 16 16 16 + DQT, Row #7: 16 16 16 16 16 16 16 16 + Approx quality factor = 91.90 (scaling=16.20 variance=0.15) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00000D58 + Frame header length = 17 + Precision = 8 + Number of Lines = 281 + Samples per Line = 450 + Image Size = 450 x 281 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000D6B + Huffman table length = 29 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 06 + Codes of length 03 bits (004 total): 00 04 05 07 + Codes of length 04 bits (003 total): 01 03 08 + Codes of length 05 bits (001 total): 02 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 010 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000D8A + Huffman table length = 82 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 02 03 04 + Codes of length 04 bits (003 total): 05 06 11 + Codes of length 05 bits (002 total): 00 12 + Codes of length 06 bits (004 total): 07 13 21 31 + Codes of length 07 bits (003 total): 22 41 51 + Codes of length 08 bits (004 total): 08 14 61 71 + Codes of length 09 bits (006 total): 15 23 32 81 91 A1 + Codes of length 10 bits (007 total): 16 42 52 55 94 B1 D2 + Codes of length 11 bits (004 total): 33 62 72 C1 + Codes of length 12 bits (007 total): 24 34 82 92 A2 D1 F0 + Codes of length 13 bits (005 total): 17 43 53 54 E1 + Codes of length 14 bits (006 total): 09 25 35 83 93 B2 + Codes of length 15 bits (007 total): 18 26 44 64 73 A3 C2 + Codes of length 16 bits (001 total): A4 + Total number of codes: 063 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000DDE + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 04 05 06 07 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 02 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000DFC + Huffman table length = 76 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (004 total): 00 03 04 21 + Codes of length 05 bits (003 total): 05 12 31 + Codes of length 06 bits (004 total): 06 41 51 61 + Codes of length 07 bits (006 total): 13 22 71 81 91 A1 + Codes of length 08 bits (006 total): 07 14 32 52 B1 D1 + Codes of length 09 bits (007 total): 15 42 53 62 72 92 C1 + Codes of length 10 bits (005 total): 23 33 A2 E1 F0 + Codes of length 11 bits (005 total): 16 17 34 82 B2 + Codes of length 12 bits (007 total): 24 35 54 63 73 D2 F1 + Codes of length 13 bits (004 total): 08 25 93 C2 + Codes of length 14 bits (003 total): 43 C3 D3 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 057 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000E4A + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00000E58 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0000D754.0 + + Compression stats: + Compression Ratio: 7.37:1 + Bits per pixel: 3.26:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 344 ( 16%) + # codes of length 03 bits: 1157 ( 55%) + # codes of length 04 bits: 453 ( 22%) + # codes of length 05 bits: 102 ( 5%) + # codes of length 06 bits: 32 ( 2%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 216 ( 21%) + # codes of length 03 bits: 672 ( 64%) + # codes of length 04 bits: 77 ( 7%) + # codes of length 05 bits: 59 ( 6%) + # codes of length 06 bits: 20 ( 2%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 11146 ( 23%) + # codes of length 03 bits: 21025 ( 43%) + # codes of length 04 bits: 8376 ( 17%) + # codes of length 05 bits: 3259 ( 7%) + # codes of length 06 bits: 2911 ( 6%) + # codes of length 07 bits: 840 ( 2%) + # codes of length 08 bits: 696 ( 1%) + # codes of length 09 bits: 499 ( 1%) + # codes of length 10 bits: 295 ( 1%) + # codes of length 11 bits: 93 ( 0%) + # codes of length 12 bits: 85 ( 0%) + # codes of length 13 bits: 26 ( 0%) + # codes of length 14 bits: 15 ( 0%) + # codes of length 15 bits: 8 ( 0%) + # codes of length 16 bits: 1 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 5260 ( 31%) + # codes of length 03 bits: 4077 ( 24%) + # codes of length 04 bits: 4031 ( 24%) + # codes of length 05 bits: 1544 ( 9%) + # codes of length 06 bits: 912 ( 5%) + # codes of length 07 bits: 626 ( 4%) + # codes of length 08 bits: 335 ( 2%) + # codes of length 09 bits: 163 ( 1%) + # codes of length 10 bits: 58 ( 0%) + # codes of length 11 bits: 27 ( 0%) + # codes of length 12 bits: 18 ( 0%) + # codes of length 13 bits: 6 ( 0%) + # codes of length 14 bits: 3 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[167] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1017, 3, -3] RGB=[253,255,255] @ MCU[ 26, 8] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x0000D753.1 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000D754 + + +*** Searching Compression Signatures *** + + Signature: 01557A9AE226A38386271DFE13D64298 + Signature (Rotated): 0167FCEDBA3A8E8CF822163DB3564762 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[Konica Minolta Camera, In] [DiMAGE Z2 ] [ ] No + CAM:[Minolta Co., Ltd. ] [DiMAGE F100 ] [ ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5000 ] [FINE ] No + CAM:[NIKON ] [E8700 ] [FINE ] No + CAM:[NIKON ] [E885 ] [FINE ] No + CAM:[OLYMPUS CORPORATION ] [C8080WZ ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-H2 ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-P200 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-W7 ] [ ] No + SW :[IJG Library ] [092 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [092 ] + SW :[IrfanView ] [092 ] + SW :[idImager ] [092 ] + SW :[FastStone Image Viewer ] [092 ] + SW :[NeatImage ] [092 ] + SW :[Paint.NET ] [092 ] + SW :[Photomatix ] [092 ] + SW :[XnView ] [092 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/ycck.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/ycck.jpg.txt new file mode 100644 index 0000000000..717f35f3c9 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/ycck.jpg.txt @@ -0,0 +1,640 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\ycck.jpg] + Filesize: [611572] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000002 + Length = 4452 + Identifier = [Exif] + Identifier TIFF = 0x[4D4D002A 00000008] + Endian = Motorola (big) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000014 + Dir Length = 0x0007 + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 720000/10000 + [YResolution ] = 720000/10000 + [ResolutionUnit ] = Inch + [Software ] = "Adobe Photoshop CC 2015.5 (Windows)" + [DateTime ] = "2016:08:23 18:21:25" + [ExifOffset ] = @ 0x00AC + Offset to Next IFD = 0x000000D8 + + EXIF IFD1 @ Absolute 0x000000E4 + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x0136 = @ 0x0142 + [JpegIFByteCount ] = 0x[00001026] / 4134 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000B8 + Dir Length = 0x0003 + [ColorSpace ] = Uncalibrated + [ExifImageWidth ] = 0x[00000200] / 512 + [ExifImageHeight ] = 0x[00000200] / 512 + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x00001168 + Length = 6522 + Identifier = [Photoshop 3.0] + 8BIM: [0x0425] Name="" Len=[0x0010] DefinedName="Caption digest" + Caption digest = | 0x00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................ + 8BIM: [0x043A] Name="" Len=[0x00E5] DefinedName="Print Information" + Print Information = + | 0x00 00 00 10 00 00 00 01 00 00 00 00 00 0B 70 72 | ..............pr + | 0x69 6E 74 4F 75 74 70 75 74 00 00 00 05 00 00 00 | intOutput....... + | 0x00 50 73 74 53 62 6F 6F 6C 01 00 00 00 00 49 6E | .PstSbool.....In + | 0x74 65 65 6E 75 6D 00 00 00 00 49 6E 74 65 00 00 | teenum....Inte.. + | 0x00 00 43 6C 72 6D 00 00 00 0F 70 72 69 6E 74 53 | ..Clrm....printS + | 0x69 78 74 65 65 6E 42 69 74 62 6F 6F 6C 00 00 00 | ixteenBitbool... + | 0x00 0B 70 72 69 6E 74 65 72 4E 61 6D 65 54 45 58 | ..printerNameTEX + | 0x54 00 00 00 01 00 00 00 00 00 0F 70 72 69 6E 74 | T..........print + | ... + 8BIM: [0x043B] Name="" Len=[0x022D] DefinedName="Print Style" + Print Style = + | 0x00 00 00 10 00 00 00 01 00 00 00 00 00 12 70 72 | ..............pr + | 0x69 6E 74 4F 75 74 70 75 74 4F 70 74 69 6F 6E 73 | intOutputOptions + | 0x00 00 00 17 00 00 00 00 43 70 74 6E 62 6F 6F 6C | ........Cptnbool + | 0x00 00 00 00 00 43 6C 62 72 62 6F 6F 6C 00 00 00 | .....Clbrbool... + | 0x00 00 52 67 73 4D 62 6F 6F 6C 00 00 00 00 00 43 | ..RgsMbool.....C + | 0x72 6E 43 62 6F 6F 6C 00 00 00 00 00 43 6E 74 43 | rnCbool.....CntC + | 0x62 6F 6F 6C 00 00 00 00 00 4C 62 6C 73 62 6F 6F | bool.....Lblsboo + | 0x6C 00 00 00 00 00 4E 67 74 76 62 6F 6F 6C 00 00 | l.....Ngtvbool.. + | ... + 8BIM: [0x03ED] Name="" Len=[0x0010] DefinedName="ResolutionInfo structure" + Horizontal resolution = 72 pixels per inch + Width unit = cm + Vertical resolution = 72 pixels per inch + Height unit = cm + 8BIM: [0x0426] Name="" Len=[0x000E] DefinedName="Print scale" + Style = centered + X location = 0.00000 + Y location = 0.00000 + Scale = 1.00000 + 8BIM: [0x040D] Name="" Len=[0x0004] DefinedName="Global Angle" + Global Angle = 30 degrees + 8BIM: [0x0419] Name="" Len=[0x0004] DefinedName="Global Altitude" + Global Altitude = 30 + 8BIM: [0x03F3] Name="" Len=[0x0009] DefinedName="Print flags" + Labels = false + Crop marks = false + Color bars = false + Registration marks = false + Negative = false + Flip = false + Interpolate = false + Caption = false + Print flags = true + 8BIM: [0x2710] Name="" Len=[0x000A] DefinedName="Print flags information" + Version = 1 + Center crop marks = 0 + Reserved = 0 + Bleed width value = 0 + Bleed width scale = 2 + 8BIM: [0x03F5] Name="" Len=[0x0048] DefinedName="Color halftoning information" + Color halftoning information = + | 0x00 2F 66 66 00 01 00 6C 66 66 00 06 00 00 00 00 | ./ff...lff...... + | 0x00 01 00 2F 66 66 00 01 00 A1 99 9A 00 06 00 00 | .../ff.......... + | 0x00 00 00 01 00 32 00 00 00 01 00 5A 00 00 00 06 | .....2.....Z.... + | 0x00 00 00 00 00 01 00 35 00 00 00 01 00 2D 00 00 | .......5.....-.. + | 0x00 06 00 00 00 00 00 01 | ........ + 8BIM: [0x03F8] Name="" Len=[0x0070] DefinedName="Color transfer functions" + Color transfer functions = + | 0x00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF | ................ + | 0xFF FF FF FF FF FF FF FF 03 E8 00 00 00 00 FF FF | ................ + | 0xFF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF | ................ + | 0xFF FF FF FF 03 E8 00 00 00 00 FF FF FF FF FF FF | ................ + | 0xFF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF | ................ + | 0x03 E8 00 00 00 00 FF FF FF FF FF FF FF FF FF FF | ................ + | 0xFF FF FF FF FF FF FF FF FF FF FF FF 03 E8 00 00 | ................ + 8BIM: [0x0400] Name="" Len=[0x0002] DefinedName="Layer state information" + Target layer = 0 + 8BIM: [0x0402] Name="" Len=[0x0002] DefinedName="Layers group information" + Layer #0: + Layer Group = 0 + 8BIM: [0x0430] Name="" Len=[0x0001] DefinedName="Layer Groups Enabled ID" + Layer #0: + Layer Group Enabled ID = 1 + 8BIM: [0x042D] Name="" Len=[0x0006] DefinedName="Layer Selection IDs" + Num selected = 1 + Layer ID = 3 + 8BIM: [0x0408] Name="" Len=[0x0010] DefinedName="Grid and guides information" + Version = 1 + Grid Horizontal = 576 + Grid Vertical = 576 + Number of Guide Resources = 0 + 8BIM: [0x041E] Name="" Len=[0x0004] DefinedName="URL List" + URL List = | 0x00 00 00 00 | .... + 8BIM: [0x041A] Name="" Len=[0x0363] DefinedName="Slices" + Slice Header: + Version = 6 + Bound Rect (top) = 0 + Bound Rect (left) = 0 + Bound Rect (bottom) = 512 + Bound Rect (right) = 512 + Name of group of slices = "imageprocessor-logo-512" + Number of slices = 1 + ----- + Slice #0: + Slice Resource: + ID = 0 + Group ID = 0 + Origin = 0 + Name = "" + Type = 1 + Position (top) = 0 + Position (left) = 0 + Position (bottom) = 512 + Position (right) = 512 + URL = "" + Target = "" + Message = "" + Alt Tag = "" + Cell text is HTML = true + Cell text = "" + Horizontal alignment = 0 + Vertical alignment = 0 + Alpha color = 0 + Red = 0 + Green = 0 + Blue = 0 + Descriptor version = 16 + Descriptor: + Name from classID = "" + classID = "null" + Num items in descriptor = 2 + ----- + Descriptor item #0: + Key = "bounds" + OSType key = "Objc" + Descriptor: + Name from classID = "" + classID = "Rct1" + Num items in descriptor = 4 + ----- + Descriptor item #0: + Key = "Top " + OSType key = "long" + Value = 0 + Descriptor item #1: + Key = "Left" + OSType key = "long" + Value = 0 + Descriptor item #2: + Key = "Btom" + OSType key = "long" + Value = 512 + Descriptor item #3: + Key = "Rght" + OSType key = "long" + Value = 512 + ----- + Descriptor item #1: + Key = "slices" + OSType key = "VlLs" + Num items in list = 1 + ----- + Item #0: + OSType key = "" + Descriptor: + Name from classID = "" + classID = "slice" + Num items in descriptor = 18 + ----- + Descriptor item #0: + Key = "sliceID" + OSType key = "long" + Value = 0 + Descriptor item #1: + Key = "groupID" + OSType key = "long" + Value = 0 + Descriptor item #2: + Key = "origin" + OSType key = "enum" + Type = "ESliceOrigin" + Enum = "autoGenerated" + Descriptor item #3: + Key = "Type" + OSType key = "enum" + Type = "ESliceType" + Enum = "Img " + Descriptor item #4: + Key = "bounds" + OSType key = "Objc" + Descriptor: + Name from classID = "" + classID = "Rct1" + Num items in descriptor = 4 + ----- + Descriptor item #0: + Key = "Top " + OSType key = "long" + Value = 0 + Descriptor item #1: + Key = "Left" + OSType key = "long" + Value = 0 + Descriptor item #2: + Key = "Btom" + OSType key = "long" + Value = 512 + Descriptor item #3: + Key = "Rght" + OSType key = "long" + Value = 512 + ----- + Descriptor item #5: + Key = "url" + OSType key = "TEXT" + String = "" + Descriptor item #6: + Key = "null" + OSType key = "TEXT" + String = "" + Descriptor item #7: + Key = "Msge" + OSType key = "TEXT" + String = "" + Descriptor item #8: + Key = "altTag" + OSType key = "TEXT" + String = "" + Descriptor item #9: + Key = "cellTextIsHTML" + OSType key = "bool" + Value = true + Descriptor item #10: + Key = "cellText" + OSType key = "TEXT" + String = "" + Descriptor item #11: + Key = "horzAlign" + OSType key = "enum" + Type = "ESliceHorzAlign" + Enum = "default" + Descriptor item #12: + Key = "vertAlign" + OSType key = "enum" + Type = "ESliceVertAlign" + Enum = "default" + Descriptor item #13: + Key = "bgColorType" + OSType key = "enum" + Type = "ESliceBGColorType" + Enum = "None" + Descriptor item #14: + Key = "topOutset" + OSType key = "long" + Value = 0 + Descriptor item #15: + Key = "leftOutset" + OSType key = "long" + Value = 0 + Descriptor item #16: + Key = "bottomOutset" + OSType key = "long" + Value = 0 + Descriptor item #17: + Key = "rightOutset" + OSType key = "long" + Value = 0 + ----- + ----- + ----- + ----- + 8BIM: [0x0428] Name="" Len=[0x000C] DefinedName="Pixel Aspect Ratio" + Version = 2 + X/Y Ratio = 1.00000 + 8BIM: [0x0414] Name="" Len=[0x0004] DefinedName="Document-specific IDs seed number" + Base value = 3 + 8BIM: [0x040C] Name="" Len=[0x1042] DefinedName="Thumbnail resources" + Format = 1 + Width of thumbnail = 160 pixels + Height of thumbnail = 160 pixels + Widthbytes = 480 bytes + Total size = 76800 bytes + Size after compression = 4134 bytes + Bits per pixel = 24 bits + Number of planes = 1 + JFIF data @ 0x00001A3C + 8BIM: [0x0421] Name="" Len=[0x0061] DefinedName="Version Info" + Version = 1 + hasRealMergedData = 1 + Writer name = "Adobe Photoshop" + Reader name = "Adobe Photoshop CC 2015.5" + File version = 1 + 8BIM: [0x0406] Name="" Len=[0x0007] DefinedName="JPEG quality" + Photoshop Save As Quality = 8 + Photoshop Save Format = "Standard" + Photoshop Save Progressive Scans = "3 Scans" + ??? = 1 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00002AE4 + Length = 3685 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0000394B + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 9 + Profile Size : 557168 bytes + Preferred CMM Type : 'ADBE' (0x41444245) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Output Device profile ('prtr' (0x70727472)) + Data Colour Space : cmykData ('CMYK' (0x434D594B)) + Profile connection space (PCS) : 'Lab ' (0x4C616220) + Profile creation date : 2000-07-26 05:41:53 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Apple Computer, Inc. ('APPL' (0x4150504C)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : 'ADBE' (0x41444245) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Media-Relative Colorimetric + Profile creator : 'ADBE' (0x41444245) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0001392F + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 2 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00023913 + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 3 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000338F7 + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 4 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000438DB + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 5 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000538BF + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 6 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000638A3 + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 7 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00073887 + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 8 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0008386B + Length = 33264 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 9 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x0008BA5D + Length = 14 + DCTEncodeVersion = 100 + APP14Flags0 = 0 + APP14Flags1 = 0 + ColorTransform = 2 [YCCK] + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0008BA6D + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 9 11 12 16 + DQT, Row #1: 4 5 5 6 8 10 12 12 + DQT, Row #2: 4 5 5 6 10 12 12 12 + DQT, Row #3: 6 6 6 11 12 12 12 12 + DQT, Row #4: 9 8 10 12 12 12 12 12 + DQT, Row #5: 11 10 12 12 12 12 12 12 + DQT, Row #6: 12 12 12 12 12 12 12 12 + DQT, Row #7: 16 12 12 12 12 12 12 12 + Approx quality factor = 88.28 (scaling=23.43 variance=111.68) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 7 7 13 24 20 20 17 17 + DQT, Row #1: 7 12 16 14 14 12 12 12 + DQT, Row #2: 13 16 14 14 12 12 12 12 + DQT, Row #3: 24 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 90.19 (scaling=19.62 variance=201.04) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0008BAF3 + Frame header length = 20 + Precision = 8 + Number of Lines = 512 + Samples per Line = 512 + Image Size = 512 x 512 + Raw Image Orientation = Landscape + Number of Img components = 4 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Cr) + Component[4]: ID=0x04, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (K) + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x0008BB09 + Length = 4 + interval = 64 + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0008BB0F + Huffman table length = 418 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (007 total): 04 05 03 02 06 01 00 + Codes of length 04 bits (001 total): 07 + Codes of length 05 bits (001 total): 08 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (001 total): 0A + Codes of length 08 bits (001 total): 0B + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 00 + Codes of length 03 bits (002 total): 02 03 + Codes of length 04 bits (003 total): 04 05 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 11 04 00 + Codes of length 05 bits (003 total): 05 21 12 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 51 06 13 61 + Codes of length 08 bits (002 total): 22 71 + Codes of length 09 bits (006 total): 81 14 32 91 A1 07 + Codes of length 10 bits (007 total): 15 B1 42 23 C1 52 D1 + Codes of length 11 bits (003 total): E1 33 16 + Codes of length 12 bits (004 total): 62 F0 24 72 + Codes of length 13 bits (002 total): 82 F1 + Codes of length 14 bits (006 total): 25 43 34 53 92 A2 + Codes of length 15 bits (002 total): B2 63 + Codes of length 16 bits (115 total): 73 C2 35 44 27 93 A3 B3 36 17 54 64 74 C3 D2 E2 + 08 26 83 09 0A 18 19 84 94 45 46 A4 B4 56 D3 55 + 28 1A F2 E3 F3 C4 D4 E4 F4 65 75 85 95 A5 B5 C5 + D5 E5 F5 66 76 86 96 A6 B6 C6 D6 E6 F6 37 47 57 + 67 77 87 97 A7 B7 C7 D7 E7 F7 38 48 58 68 78 88 + 98 A8 B8 C8 D8 E8 F8 29 39 49 59 69 79 89 99 A9 + B9 C9 D9 E9 F9 2A 3A 4A 5A 6A 7A 8A 9A AA BA CA + DA EA FA + Total number of codes: 162 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 00 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (002 total): 04 21 + Codes of length 06 bits (003 total): 12 31 41 + Codes of length 07 bits (005 total): 05 51 13 61 22 + Codes of length 08 bits (005 total): 06 71 81 91 32 + Codes of length 09 bits (004 total): A1 B1 F0 14 + Codes of length 10 bits (005 total): C1 D1 E1 23 42 + Codes of length 11 bits (006 total): 15 52 62 72 F1 33 + Codes of length 12 bits (004 total): 24 34 43 82 + Codes of length 13 bits (008 total): 16 92 53 25 A2 63 B2 C2 + Codes of length 14 bits (003 total): 07 73 D2 + Codes of length 15 bits (003 total): 35 E2 44 + Codes of length 16 bits (109 total): 83 17 54 93 08 09 0A 18 19 26 36 45 1A 27 64 74 + 55 37 F2 A3 B3 C3 28 29 D3 E3 F3 84 94 A4 B4 C4 + D4 E4 F4 65 75 85 95 A5 B5 C5 D5 E5 F5 46 56 66 + 76 86 96 A6 B6 C6 D6 E6 F6 47 57 67 77 87 97 A7 + B7 C7 D7 E7 F7 38 48 58 68 78 88 98 A8 B8 C8 D8 + E8 F8 39 49 59 69 79 89 99 A9 B9 C9 D9 E9 F9 2A + 3A 4A 5A 6A 7A 8A 9A AA BA CA DA EA FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0008BCB3 + Scan header length = 14 + Number of img components = 4 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Component[4]: selector=0x04, table=0(DC),0(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support CMYK files yet. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x000954F2 + + +*** Searching Compression Signatures *** + + Signature: 01180AF3DE63318828A86409EF4013DD + Signature (Rotated): 01180AF3DE63318828A86409EF4013DD + File Offset: 0 bytes + Chroma subsampling: ?x? + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: OK [Adobe Photoshop CC 2015.5 (Windows)] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[Adobe Photoshop ] [Save As 08 ] + + NOTE: Photoshop IRB detected + NOTE: EXIF Software field recognized as from editor + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue159-MissingFF00-Progressive-Bedroom.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue159-MissingFF00-Progressive-Bedroom.jpg.txt new file mode 100644 index 0000000000..ea1f5e0f79 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue159-MissingFF00-Progressive-Bedroom.jpg.txt @@ -0,0 +1,461 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue159-MissingFF00-Progressive-Bedroom.jpg] + Filesize: [338422] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 9 14 18 22 + DQT, Row #1: 4 4 5 7 9 21 22 20 + DQT, Row #2: 5 5 6 9 14 21 25 20 + DQT, Row #3: 5 6 8 10 18 31 29 22 + DQT, Row #4: 6 8 13 20 24 39 37 28 + DQT, Row #5: 9 13 20 23 29 37 41 33 + DQT, Row #6: 18 23 28 31 37 44 43 36 + DQT, Row #7: 26 33 34 35 40 36 37 36 + Approx quality factor = 81.99 (scaling=36.03 variance=1.13) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 6 6 9 17 36 36 36 36 + DQT, Row #1: 6 8 9 24 36 36 36 36 + DQT, Row #2: 9 9 20 36 36 36 36 36 + DQT, Row #3: 17 24 36 36 36 36 36 36 + DQT, Row #4: 36 36 36 36 36 36 36 36 + DQT, Row #5: 36 36 36 36 36 36 36 36 + DQT, Row #6: 36 36 36 36 36 36 36 36 + DQT, Row #7: 36 36 36 36 36 36 36 36 + Approx quality factor = 81.88 (scaling=36.24 variance=0.48) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 2300 + Samples per Line = 2300 + Image Size = 2300 x 2300 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 27 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 01 02 + Codes of length 04 bits (003 total): 03 04 05 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000CE + Huffman table length = 26 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (001 total): 06 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 007 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000EA + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000CBBB + Huffman table length = 56 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (004 total): 00 01 02 03 + Codes of length 04 bits (005 total): 04 10 11 12 41 + Codes of length 05 bits (002 total): 21 31 + Codes of length 06 bits (005 total): 05 13 20 22 32 + Codes of length 07 bits (003 total): 15 30 42 + Codes of length 08 bits (005 total): 14 23 33 34 50 + Codes of length 09 bits (000 total): + Codes of length 10 bits (002 total): 24 40 + Codes of length 11 bits (002 total): 06 16 + Codes of length 12 bits (002 total): 43 60 + Codes of length 13 bits (002 total): 70 A0 + Codes of length 14 bits (003 total): 44 80 90 + Codes of length 15 bits (001 total): B0 + Codes of length 16 bits (001 total): 35 + Total number of codes: 037 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000CBF5 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0001A2A8 + Huffman table length = 51 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (005 total): 02 03 10 20 30 + Codes of length 05 bits (003 total): 12 13 31 + Codes of length 06 bits (004 total): 04 21 32 40 + Codes of length 07 bits (002 total): 14 51 + Codes of length 08 bits (002 total): 05 41 + Codes of length 09 bits (002 total): 33 50 + Codes of length 10 bits (001 total): 22 + Codes of length 11 bits (004 total): 15 52 61 70 + Codes of length 12 bits (003 total): 23 42 60 + Codes of length 13 bits (000 total): + Codes of length 14 bits (003 total): 71 A0 B0 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 032 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0001A2DD + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0001BB1E + Huffman table length = 50 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (005 total): 02 03 10 20 30 + Codes of length 05 bits (003 total): 12 13 31 + Codes of length 06 bits (004 total): 04 21 32 40 + Codes of length 07 bits (002 total): 14 51 + Codes of length 08 bits (003 total): 05 41 50 + Codes of length 09 bits (001 total): 22 + Codes of length 10 bits (000 total): + Codes of length 11 bits (001 total): 61 + Codes of length 12 bits (004 total): 23 33 60 70 + Codes of length 13 bits (002 total): 15 43 + Codes of length 14 bits (003 total): 52 A0 B0 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 031 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0001BB52 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0001D49C + Huffman table length = 67 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (000 total): + Codes of length 04 bits (004 total): 10 11 21 31 + Codes of length 05 bits (005 total): 02 41 51 71 81 + Codes of length 06 bits (001 total): 20 + Codes of length 07 bits (006 total): 12 22 30 61 91 A1 + Codes of length 08 bits (004 total): 03 32 33 C1 + Codes of length 09 bits (002 total): 40 50 + Codes of length 10 bits (010 total): 13 23 42 52 72 82 B1 D1 E1 F0 + Codes of length 11 bits (002 total): 34 62 + Codes of length 12 bits (003 total): 60 92 F1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (002 total): 24 80 + Codes of length 15 bits (000 total): + Codes of length 16 bits (007 total): 04 70 43 A2 14 C0 D0 + Total number of codes: 048 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0001D4E1 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000291D6 + Huffman table length = 44 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 11 21 + Codes of length 04 bits (002 total): 31 41 + Codes of length 05 bits (001 total): 51 + Codes of length 06 bits (003 total): 10 61 71 + Codes of length 07 bits (003 total): 81 91 A1 + Codes of length 08 bits (003 total): 20 B1 F0 + Codes of length 09 bits (004 total): 30 C1 D1 E1 + Codes of length 10 bits (003 total): 40 50 F1 + Codes of length 11 bits (001 total): 60 + Codes of length 12 bits (001 total): 70 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 025 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00029204 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00044080 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00047DC7 + Huffman table length = 45 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (004 total): 10 30 31 61 + Codes of length 05 bits (006 total): 20 21 40 41 51 71 + Codes of length 06 bits (002 total): 50 60 + Codes of length 07 bits (003 total): 81 91 A1 + Codes of length 08 bits (001 total): B1 + Codes of length 09 bits (000 total): + Codes of length 10 bits (002 total): 70 F0 + Codes of length 11 bits (002 total): C1 D1 + Codes of length 12 bits (003 total): A0 B0 F1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 026 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00047DF6 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00048BD6 + Huffman table length = 45 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (004 total): 20 30 31 61 + Codes of length 05 bits (006 total): 10 21 40 41 51 71 + Codes of length 06 bits (002 total): 50 81 + Codes of length 07 bits (003 total): 60 91 B1 + Codes of length 08 bits (001 total): A1 + Codes of length 09 bits (000 total): + Codes of length 10 bits (002 total): 70 C1 + Codes of length 11 bits (002 total): 80 F0 + Codes of length 12 bits (003 total): A0 B0 D1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 026 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00048C05 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00049AE7 + Huffman table length = 48 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 70 + Codes of length 03 bits (001 total): 00 + Codes of length 04 bits (007 total): 01 11 31 41 51 80 91 + Codes of length 05 bits (003 total): 10 21 81 + Codes of length 06 bits (002 total): 50 60 + Codes of length 07 bits (005 total): 20 40 61 71 D1 + Codes of length 08 bits (004 total): 30 B1 E1 F1 + Codes of length 09 bits (002 total): A1 F0 + Codes of length 10 bits (003 total): A0 C0 C1 + Codes of length 11 bits (001 total): D0 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 029 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00049B19 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x000529F4 + + +*** Searching Compression Signatures *** + + Signature: 0138A8D4ECE59F41D2EB9AF5168B6675 + Signature (Rotated): 01CA9A809F737BA668C16DDE52E74092 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C700UZ ] [ ] No + SW :[IJG Library ] [082 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [082 ] + SW :[IrfanView ] [082 ] + SW :[idImager ] [082 ] + SW :[FastStone Image Viewer ] [082 ] + SW :[NeatImage ] [082 ] + SW :[Paint.NET ] [082 ] + SW :[Photomatix ] [082 ] + SW :[XnView ] [082 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue159-MissingFF00-Progressive-Girl.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue159-MissingFF00-Progressive-Girl.jpg.txt new file mode 100644 index 0000000000..4858b4ea18 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue159-MissingFF00-Progressive-Girl.jpg.txt @@ -0,0 +1,520 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue159-MissingFF00-Progressive-Girl.jpg] + Filesize: [60927] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.2] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x00000014 + Length = 132 + Identifier = [Photoshop 3.0] + 8BIM: [0x0404] Name="" Len=[0x0067] DefinedName="IPTC-NAA record" + IPTC [002:040] Special Instructions = "FBMD01000a820d0000192d00007a4400006e460000a9470000a44e00000b7b0000cc830000e0880000a08c0000ffed0000" + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0000009A + Length = 3064 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 3048 bytes + Preferred CMM Type : '....' (0x00000000) + Profile Version : 0.2.0.0 (0x02000000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 2009-03-27 21:36:31 + Profile file signature : 'acsp' (0x61637370) + Primary platform : ? (0x00000000) ('....' (0x00000000)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : '....' (0x00000000) + Device Model : '....' (0x00000000) + Device attributes : 0x00000001_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : '....' (0x00000000) + Profile ID : 0x29F83DDE_AFF255AE_7842FAE4_CA83390D + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000C94 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 9 6 6 9 14 23 30 35 + DQT, Row #1: 7 7 8 11 15 34 35 32 + DQT, Row #2: 8 8 9 14 23 33 40 32 + DQT, Row #3: 8 10 13 17 30 50 46 36 + DQT, Row #4: 10 13 21 32 39 63 60 45 + DQT, Row #5: 14 20 32 37 47 60 66 53 + DQT, Row #6: 28 37 45 50 60 70 70 59 + DQT, Row #7: 42 53 55 57 65 58 60 57 + Approx quality factor = 71.07 (scaling=57.86 variance=0.92) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000CD9 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 10 10 14 27 57 57 57 57 + DQT, Row #1: 10 12 15 38 57 57 57 57 + DQT, Row #2: 14 15 32 57 57 57 57 57 + DQT, Row #3: 27 38 57 57 57 57 57 57 + DQT, Row #4: 57 57 57 57 57 57 57 57 + DQT, Row #5: 57 57 57 57 57 57 57 57 + DQT, Row #6: 57 57 57 57 57 57 57 57 + DQT, Row #7: 57 57 57 57 57 57 57 57 + Approx quality factor = 71.23 (scaling=57.54 variance=0.18) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x00000D1E + Frame header length = 17 + Precision = 8 + Number of Lines = 990 + Samples per Line = 750 + Image Size = 750 x 990 + Raw Image Orientation = Portrait + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000D31 + Huffman table length = 27 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000D4E + Huffman table length = 24 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 005 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000D68 + Huffman table length = 24 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 005 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000D82 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002CED + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (003 total): 03 10 11 + Codes of length 05 bits (003 total): 04 12 20 + Codes of length 06 bits (004 total): 21 30 31 40 + Codes of length 07 bits (002 total): 32 41 + Codes of length 08 bits (002 total): 13 22 + Codes of length 09 bits (003 total): 05 14 50 + Codes of length 10 bits (001 total): 33 + Codes of length 11 bits (001 total): 42 + Codes of length 12 bits (001 total): 23 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002D19 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00004455 + Huffman table length = 35 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (001 total): 00 + Codes of length 04 bits (005 total): 02 10 11 20 30 + Codes of length 05 bits (001 total): 40 + Codes of length 06 bits (000 total): + Codes of length 07 bits (002 total): 12 50 + Codes of length 08 bits (003 total): 03 31 41 + Codes of length 09 bits (001 total): 21 + Codes of length 10 bits (001 total): 51 + Codes of length 11 bits (001 total): 60 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 016 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000447A + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000464C + Huffman table length = 32 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (000 total): + Codes of length 04 bits (007 total): 00 10 11 20 30 40 50 + Codes of length 05 bits (001 total): 02 + Codes of length 06 bits (001 total): 12 + Codes of length 07 bits (000 total): + Codes of length 08 bits (003 total): 21 31 70 + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 013 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000466E + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00004775 + Huffman table length = 50 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (003 total): 02 21 40 + Codes of length 05 bits (007 total): 10 12 30 31 32 50 91 + Codes of length 06 bits (003 total): 20 41 51 + Codes of length 07 bits (003 total): 60 61 71 + Codes of length 08 bits (004 total): 03 22 42 81 + Codes of length 09 bits (002 total): 13 62 + Codes of length 10 bits (001 total): 43 + Codes of length 11 bits (005 total): 23 52 70 80 A1 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 031 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000047A9 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00004E79 + Huffman table length = 41 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (003 total): 10 21 31 + Codes of length 05 bits (004 total): 41 61 71 81 + Codes of length 06 bits (002 total): 20 51 + Codes of length 07 bits (002 total): 30 91 + Codes of length 08 bits (003 total): A1 D1 F0 + Codes of length 09 bits (001 total): 40 + Codes of length 10 bits (001 total): B1 + Codes of length 11 bits (001 total): C1 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (001 total): E1 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00004EA4 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00007B0B + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000083AB + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (000 total): + Codes of length 04 bits (003 total): 10 11 20 + Codes of length 05 bits (000 total): + Codes of length 06 bits (003 total): 21 30 31 + Codes of length 07 bits (001 total): 41 + Codes of length 08 bits (001 total): 51 + Codes of length 09 bits (001 total): 40 + Codes of length 10 bits (001 total): 61 + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000083CC + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000088BF + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (003 total): 00 10 11 + Codes of length 04 bits (001 total): 20 + Codes of length 05 bits (001 total): 30 + Codes of length 06 bits (000 total): + Codes of length 07 bits (003 total): 21 31 41 + Codes of length 08 bits (001 total): 40 + Codes of length 09 bits (001 total): 51 + Codes of length 10 bits (001 total): 71 + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000088E0 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00008C75 + Huffman table length = 41 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (002 total): 41 51 + Codes of length 06 bits (001 total): 61 + Codes of length 07 bits (003 total): 10 71 81 + Codes of length 08 bits (003 total): 91 A1 B1 + Codes of length 09 bits (005 total): 20 30 C1 D1 F1 + Codes of length 10 bits (001 total): E1 + Codes of length 11 bits (001 total): F0 + Codes of length 12 bits (001 total): 40 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00008CA0 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000EDFD + + +*** Searching Compression Signatures *** + + Signature: 01B8FDD60747E53114DC15797CC09B4E + Signature (Rotated): 011975EE86201F10E48E4F365C73A839 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[IJG Library ] [071 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [071 ] + SW :[IrfanView ] [071 ] + SW :[idImager ] [071 ] + SW :[FastStone Image Viewer ] [071 ] + SW :[NeatImage ] [071 ] + SW :[Paint.NET ] [071 ] + SW :[Photomatix ] [071 ] + SW :[XnView ] [071 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue178-BadCoeffsProgressive-Lemon.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue178-BadCoeffsProgressive-Lemon.jpg.txt new file mode 100644 index 0000000000..af39df365c --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue178-BadCoeffsProgressive-Lemon.jpg.txt @@ -0,0 +1,471 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue178-BadCoeffsProgressive-Lemon.jpg] + Filesize: [279270] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 2 2 1 + DQT, Row #4: 1 1 1 1 1 2 2 2 + DQT, Row #5: 1 1 1 1 2 2 2 2 + DQT, Row #6: 1 1 2 2 2 2 2 2 + DQT, Row #7: 1 2 2 2 2 2 2 2 + Approx quality factor = 98.32 (scaling=3.35 variance=5.00) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 1 1 1 1 2 2 2 2 + DQT, Row #1: 1 1 1 1 2 2 2 2 + DQT, Row #2: 1 1 1 2 2 2 2 2 + DQT, Row #3: 1 1 2 2 2 2 2 2 + DQT, Row #4: 2 2 2 2 2 2 2 2 + DQT, Row #5: 2 2 2 2 2 2 2 2 + DQT, Row #6: 2 2 2 2 2 2 2 2 + DQT, Row #7: 2 2 2 2 2 2 2 2 + Approx quality factor = 98.83 (scaling=2.34 variance=0.89) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 710 + Samples per Line = 710 + Image Size = 710 x 710 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 30 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 05 + Codes of length 03 bits (004 total): 03 04 06 07 + Codes of length 04 bits (003 total): 00 02 08 + Codes of length 05 bits (001 total): 01 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (001 total): 0A + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 011 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000D1 + Huffman table length = 29 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 03 + Codes of length 03 bits (005 total): 00 01 02 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 010 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000F0 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002D06 + Huffman table length = 49 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 02 + Codes of length 03 bits (004 total): 00 01 03 04 + Codes of length 04 bits (002 total): 05 11 + Codes of length 05 bits (002 total): 06 12 + Codes of length 06 bits (002 total): 13 21 + Codes of length 07 bits (002 total): 07 14 + Codes of length 08 bits (001 total): 22 + Codes of length 09 bits (003 total): 10 15 31 + Codes of length 10 bits (004 total): 16 23 32 41 + Codes of length 11 bits (001 total): 20 + Codes of length 12 bits (004 total): 08 30 33 50 + Codes of length 13 bits (003 total): 24 40 42 + Codes of length 14 bits (001 total): 34 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 030 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002D39 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00007ADB + Huffman table length = 72 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 00 02 03 + Codes of length 04 bits (002 total): 04 11 + Codes of length 05 bits (003 total): 12 21 31 + Codes of length 06 bits (005 total): 05 22 41 51 61 + Codes of length 07 bits (005 total): 06 13 71 81 A1 + Codes of length 08 bits (005 total): 14 32 91 B1 F0 + Codes of length 09 bits (006 total): 23 42 52 C1 D1 E1 + Codes of length 10 bits (004 total): 10 15 33 62 + Codes of length 11 bits (003 total): 07 82 F1 + Codes of length 12 bits (006 total): 20 24 30 43 72 A2 + Codes of length 13 bits (006 total): 16 34 53 92 B2 E2 + Codes of length 14 bits (003 total): 25 44 93 + Codes of length 15 bits (001 total): D2 + Codes of length 16 bits (000 total): + Total number of codes: 053 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00007B25 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000A7E3 + Huffman table length = 74 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 02 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (005 total): 05 12 21 31 41 + Codes of length 06 bits (005 total): 06 13 22 51 61 + Codes of length 07 bits (004 total): 32 71 81 91 + Codes of length 08 bits (006 total): 14 42 52 A1 B1 F0 + Codes of length 09 bits (008 total): 07 10 15 23 62 C1 D1 E1 + Codes of length 10 bits (004 total): 33 43 72 92 + Codes of length 11 bits (004 total): 24 82 A2 F1 + Codes of length 12 bits (004 total): 16 34 63 D2 + Codes of length 13 bits (006 total): 20 40 53 B2 C2 E2 + Codes of length 14 bits (003 total): 17 25 30 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 055 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000A82F + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000E96D + Huffman table length = 84 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (003 total): 00 03 21 + Codes of length 05 bits (005 total): 04 12 31 41 51 + Codes of length 06 bits (004 total): 05 22 61 71 + Codes of length 07 bits (006 total): 13 32 81 91 A1 F0 + Codes of length 08 bits (008 total): 10 14 23 42 52 B1 C1 D1 + Codes of length 09 bits (003 total): 33 62 E1 + Codes of length 10 bits (005 total): 06 72 82 92 F1 + Codes of length 11 bits (006 total): 15 20 24 43 53 A2 + Codes of length 12 bits (004 total): 30 34 63 73 + Codes of length 13 bits (004 total): 44 83 B2 C2 + Codes of length 14 bits (005 total): 40 50 93 A3 D2 + Codes of length 15 bits (002 total): 16 25 + Codes of length 16 bits (007 total): 26 35 54 60 64 B3 E2 + Total number of codes: 065 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000E9C3 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0001AD55 + Huffman table length = 40 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 11 21 + Codes of length 04 bits (002 total): 00 31 + Codes of length 05 bits (002 total): 41 51 + Codes of length 06 bits (002 total): 61 71 + Codes of length 07 bits (002 total): 81 91 + Codes of length 08 bits (002 total): A1 B1 + Codes of length 09 bits (003 total): C1 D1 F0 + Codes of length 10 bits (000 total): + Codes of length 11 bits (003 total): 10 E1 F1 + Codes of length 12 bits (001 total): 20 + Codes of length 13 bits (001 total): 30 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 021 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0001AD7F + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000287B1 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00028DB3 + Huffman table length = 39 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 11 21 + Codes of length 04 bits (002 total): 00 31 + Codes of length 05 bits (001 total): 41 + Codes of length 06 bits (003 total): 51 61 71 + Codes of length 07 bits (003 total): 81 91 F0 + Codes of length 08 bits (005 total): A1 B1 C1 D1 E1 + Codes of length 09 bits (001 total): F1 + Codes of length 10 bits (001 total): 10 + Codes of length 11 bits (001 total): 20 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 020 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00028DDC + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0002CD0C + Huffman table length = 41 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 11 21 + Codes of length 04 bits (002 total): 00 31 + Codes of length 05 bits (002 total): 41 51 + Codes of length 06 bits (001 total): 61 + Codes of length 07 bits (004 total): 71 81 91 F0 + Codes of length 08 bits (002 total): A1 B1 + Codes of length 09 bits (003 total): C1 D1 E1 + Codes of length 10 bits (001 total): F1 + Codes of length 11 bits (001 total): 30 + Codes of length 12 bits (001 total): 10 + Codes of length 13 bits (001 total): 20 + Codes of length 14 bits (001 total): 40 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0002CD37 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00031187 + Huffman table length = 38 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 11 + Codes of length 03 bits (001 total): 21 + Codes of length 04 bits (000 total): + Codes of length 05 bits (003 total): 00 31 41 + Codes of length 06 bits (000 total): + Codes of length 07 bits (002 total): 51 61 + Codes of length 08 bits (002 total): 71 81 + Codes of length 09 bits (002 total): 91 A1 + Codes of length 10 bits (002 total): B1 C1 + Codes of length 11 bits (003 total): D1 E1 F0 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (001 total): 10 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 019 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000311AF + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x000442E4 + + +*** Searching Compression Signatures *** + + Signature: 01C7F83908166C226C06A44017421732 + Signature (Rotated): 01D3EFDD3855C42AE3E0E6289F1A6726 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[Canon ] [Canon EOS-1Ds Mark II ] [fine ] No + CAM:[CASIO COMPUTER CO.,LTD. ] [EX-Z1000 ] [ ] Yes + CAM:[NIKON ] [NIKON D2X ] [FINE ] No + CAM:[NIKON ] [NIKON D3 ] [FINE ] No + CAM:[SIGMA ] [SIGMA SD10 ] [Qual:12 ] No + CAM:[SIGMA ] [SIGMA SD10 ] [Qual:12 ] No + CAM:[SIGMA ] [SIGMA SD14 ] [Qual:12 ] No + CAM:[SIGMA ] [SIGMA SD14 ] [Qual:12 ] No + CAM:[SONY ] [DSC-H2 ] [ ] No + CAM:[SONY ] [DSC-R1 ] [ ] No + CAM:[SONY ] [DSC-W7 ] [ ] No + SW :[Digital Photo Professiona] [09 ] + SW :[IJG Library ] [099 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [099 ] + SW :[IrfanView ] [099 ] + SW :[idImager ] [099 ] + SW :[FastStone Image Viewer ] [099 ] + SW :[NeatImage ] [099 ] + SW :[Paint.NET ] [099 ] + SW :[Photomatix ] [099 ] + SW :[XnView ] [099 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue214-CriticalEOF .jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue214-CriticalEOF .jpg.txt new file mode 100644 index 0000000000..f5b6d277d7 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue214-CriticalEOF .jpg.txt @@ -0,0 +1,94 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue214-CriticalEOF .jpg] + Filesize: [35601] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 300 x 300 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 39251 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0015 + [Make ] = "NIKON CORPORATION" + [Model ] = "NIKON D40" + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 300/1 + [YResolution ] = 300/1 + [ResolutionUnit ] = Inch + [Software ] = "Ver.1.10 " + [DateTime ] = "2009:02:17 08:30:16" + [YCbCrPositioning ] = Co-sited + [ExifOffset ] = @ 0x015C + [CustomRendered ] = Normal process + [ExposureMode ] = Auto exposure + [WhiteBalance ] = Auto white balance + [SceneCaptureType ] = Standard + Offset to Next IFD = 0x00007652 + + EXIF IFD1 @ Absolute 0x00007670 + Dir Length = 0x0007 + [Compression ] = JPEG + [XResolution ] = 300/1 + [YResolution ] = 300/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x76BC = @ 0x76DA + [JpegIFByteCount ] = 0x[0000228F] / 8847 + [YCbCrPositioning ] = Co-sited + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x0000017A + Dir Length = 0x001C + [ExposureTime ] = 10/1250 s + [FNumber ] = F5.6 + [ExposureProgram ] = Not defined + [ISOSpeedRatings ] = 220 + [ExifVersion ] = 02.21 + [DateTimeOriginal ] = "2009:02:17 08:30:16" + [DateTimeDigitized ] = "2009:02:17 08:30:15" + [ComponentsConfiguration ] = [Y Cb Cr .] + [CompressedBitsPerPixel ] = 1/1 + [ExposureBiasValue ] = 0.00 eV + [MaxApertureValue ] = 41/10 + [MeteringMode ] = Pattern + [LightSource ] = unknown + [Flash ] = Flash did not fire + [FocalLength ] = 30 mm + [MakerNote ] = @ 0x030A + [UserComment ] = " " + [SubSecTime ] = "60" + [SubSecTimeOriginal ] = "60" + [SubSecTimeDigitized ] = "60" + [FlashPixVersion ] = 01.00 + [ColorSpace ] = sRGB + [ExifImageWidth ] = 3008 + [ExifImageHeight ] = 2000 + [SensingMethod ] = One-chip color area sensor + [FileSource ] = DSC + [SceneType ] = A directly photographed image + [CFAPattern ] = + = [ Blu Grn ] + = [ Grn Red ] + + EXIF MakerIFD @ Absolute 0x00000328 + Makernote decode option not enabled. + +ERROR: Early EOF - file may be missing EOI diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue385-BadZigZag-Progressive.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue385-BadZigZag-Progressive.jpg.txt new file mode 100644 index 0000000000..1f98e67dc1 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue385-BadZigZag-Progressive.jpg.txt @@ -0,0 +1,468 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue385-BadZigZag-Progressive.jpg] + Filesize: [388517] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 5 3 3 5 7 12 15 18 + DQT, Row #1: 4 4 4 6 8 17 18 17 + DQT, Row #2: 4 4 5 7 12 17 21 17 + DQT, Row #3: 4 5 7 9 15 26 24 19 + DQT, Row #4: 5 7 11 17 20 33 31 23 + DQT, Row #5: 7 11 17 19 24 31 34 28 + DQT, Row #6: 15 19 23 26 31 36 36 30 + DQT, Row #7: 22 28 29 29 34 30 31 30 + Approx quality factor = 84.93 (scaling=30.13 variance=1.05) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 5 5 7 14 30 30 30 30 + DQT, Row #1: 5 6 8 20 30 30 30 30 + DQT, Row #2: 7 8 17 30 30 30 30 30 + DQT, Row #3: 14 20 30 30 30 30 30 30 + DQT, Row #4: 30 30 30 30 30 30 30 30 + DQT, Row #5: 30 30 30 30 30 30 30 30 + DQT, Row #6: 30 30 30 30 30 30 30 30 + DQT, Row #7: 30 30 30 30 30 30 30 30 + Approx quality factor = 84.93 (scaling=30.15 variance=0.29) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 1440 + Samples per Line = 1920 + Image Size = 1920 x 1440 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 28 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (003 total): 02 03 04 + Codes of length 04 bits (001 total): 05 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (001 total): 08 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000CF + Huffman table length = 25 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 006 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000EA + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00007E0B + Huffman table length = 55 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (003 total): 04 12 21 + Codes of length 06 bits (002 total): 05 10 + Codes of length 07 bits (004 total): 13 20 22 31 + Codes of length 08 bits (004 total): 06 14 30 41 + Codes of length 09 bits (005 total): 15 32 33 34 40 + Codes of length 10 bits (005 total): 23 24 35 42 50 + Codes of length 11 bits (000 total): + Codes of length 12 bits (002 total): 25 70 + Codes of length 13 bits (003 total): 16 44 60 + Codes of length 14 bits (001 total): 36 + Codes of length 15 bits (001 total): 45 + Codes of length 16 bits (001 total): 43 + Total number of codes: 036 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00007E44 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00012C0C + Huffman table length = 46 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (004 total): 02 10 12 20 + Codes of length 05 bits (000 total): + Codes of length 06 bits (004 total): 03 21 30 31 + Codes of length 07 bits (006 total): 13 32 40 41 50 51 + Codes of length 08 bits (002 total): 22 61 + Codes of length 09 bits (002 total): 04 60 + Codes of length 10 bits (003 total): 23 33 71 + Codes of length 11 bits (001 total): 42 + Codes of length 12 bits (001 total): 05 + Codes of length 13 bits (001 total): 43 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 027 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00012C3C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00013C45 + Huffman table length = 43 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (004 total): 02 10 12 20 + Codes of length 05 bits (001 total): 30 + Codes of length 06 bits (004 total): 03 21 31 40 + Codes of length 07 bits (002 total): 41 50 + Codes of length 08 bits (002 total): 13 51 + Codes of length 09 bits (002 total): 22 60 + Codes of length 10 bits (003 total): 32 42 61 + Codes of length 11 bits (001 total): 04 + Codes of length 12 bits (001 total): 81 + Codes of length 13 bits (001 total): 71 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 024 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00013C72 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000148F2 + Huffman table length = 75 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (000 total): + Codes of length 04 bits (004 total): 02 11 21 31 + Codes of length 05 bits (002 total): 03 10 + Codes of length 06 bits (006 total): 12 20 22 32 41 51 + Codes of length 07 bits (007 total): 04 30 33 61 71 81 91 + Codes of length 08 bits (005 total): 13 40 50 52 72 + Codes of length 09 bits (007 total): 23 34 42 62 82 92 A1 + Codes of length 10 bits (001 total): B1 + Codes of length 11 bits (006 total): 14 60 70 73 C1 E1 + Codes of length 12 bits (005 total): 05 63 83 A2 D1 + Codes of length 13 bits (004 total): 24 43 53 93 + Codes of length 14 bits (002 total): 74 F0 + Codes of length 15 bits (002 total): 15 B2 + Codes of length 16 bits (003 total): 35 E2 F1 + Total number of codes: 056 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0001493F + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0001BD13 + Huffman table length = 44 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (002 total): 41 51 + Codes of length 06 bits (002 total): 10 61 + Codes of length 07 bits (001 total): 71 + Codes of length 08 bits (004 total): 20 81 91 A1 + Codes of length 09 bits (002 total): 30 B1 + Codes of length 10 bits (002 total): C1 F0 + Codes of length 11 bits (003 total): 40 D1 F1 + Codes of length 12 bits (001 total): E1 + Codes of length 13 bits (001 total): 50 + Codes of length 14 bits (001 total): 60 + Codes of length 15 bits (001 total): 70 + Codes of length 16 bits (000 total): + Total number of codes: 025 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0001BD41 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0002C20D + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0002E1DF + Huffman table length = 37 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (000 total): + Codes of length 05 bits (002 total): 21 31 + Codes of length 06 bits (002 total): 10 41 + Codes of length 07 bits (003 total): 20 51 61 + Codes of length 08 bits (001 total): 71 + Codes of length 09 bits (001 total): 30 + Codes of length 10 bits (001 total): 81 + Codes of length 11 bits (001 total): 40 + Codes of length 12 bits (001 total): 91 + Codes of length 13 bits (001 total): A1 + Codes of length 14 bits (001 total): B1 + Codes of length 15 bits (001 total): C1 + Codes of length 16 bits (000 total): + Total number of codes: 018 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0002E206 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000313D7 + Huffman table length = 36 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (003 total): 10 21 31 + Codes of length 05 bits (000 total): + Codes of length 06 bits (003 total): 20 41 51 + Codes of length 07 bits (001 total): 61 + Codes of length 08 bits (001 total): 71 + Codes of length 09 bits (001 total): 30 + Codes of length 10 bits (001 total): 81 + Codes of length 11 bits (001 total): 40 + Codes of length 12 bits (001 total): 91 + Codes of length 13 bits (001 total): B1 + Codes of length 14 bits (001 total): A1 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 017 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000313FD + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00033E31 + Huffman table length = 40 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (002 total): 41 51 + Codes of length 06 bits (002 total): 61 71 + Codes of length 07 bits (002 total): 81 91 + Codes of length 08 bits (002 total): A1 B1 + Codes of length 09 bits (003 total): 10 C1 D1 + Codes of length 10 bits (001 total): F0 + Codes of length 11 bits (001 total): E1 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (001 total): 20 + Codes of length 14 bits (001 total): 30 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 021 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00033E5B + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0005EDA3 + + +*** Searching Compression Signatures *** + + Signature: 0155D875C95B74D0F3C5835A62516F48 + Signature (Rotated): 01D38A25358EB7649A254E19F1D46600 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[Nokia ] [N73 ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 8100 ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + SW :[IJG Library ] [085 ] + SW :[Picasa ] [085 (Normal) ] + SW :[ZoomBrowser EX ] [medium ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [085 ] + SW :[IrfanView ] [085 ] + SW :[idImager ] [085 ] + SW :[FastStone Image Viewer ] [085 ] + SW :[NeatImage ] [085 ] + SW :[Paint.NET ] [085 ] + SW :[Photomatix ] [085 ] + SW :[XnView ] [085 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue394-MultiHuffmanBaseline-Speakers.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue394-MultiHuffmanBaseline-Speakers.jpg.txt new file mode 100644 index 0000000000..22e9a99dd2 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue394-MultiHuffmanBaseline-Speakers.jpg.txt @@ -0,0 +1,438 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue394-MultiHuffmanBaseline-Speakers.jpg] + Filesize: [257401] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00000002 + Length = 576 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 560 bytes + Preferred CMM Type : 'ADBE' (0x41444245) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 1999-06-03 00:00:00 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Apple Computer, Inc. ('APPL' (0x4150504C)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : 'none' (0x6E6F6E65) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'ADBE' (0x41444245) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x00000244 + Length = 90 + Identifier = [Photoshop 3.0] + 8BIM: [0x0404] Name="" Len=[0x003D] DefinedName="IPTC-NAA record" + IPTC [001:090] Coded Character Set = "%G" + IPTC [002:000] Record Version = 3 + IPTC [002:055] Date Created = "20161215" + IPTC [002:060] Time Created = "043026-0600" + IPTC [002:221] ? = ??? + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000002A0 + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 9 11 12 16 + DQT, Row #1: 4 5 5 6 8 10 12 12 + DQT, Row #2: 4 5 5 6 10 12 12 12 + DQT, Row #3: 6 6 6 11 12 12 12 12 + DQT, Row #4: 9 8 10 12 12 12 12 12 + DQT, Row #5: 11 10 12 12 12 12 12 12 + DQT, Row #6: 12 12 12 12 12 12 12 12 + DQT, Row #7: 16 12 12 12 12 12 12 12 + Approx quality factor = 88.28 (scaling=23.43 variance=111.68) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 7 7 13 24 20 20 17 17 + DQT, Row #1: 7 12 16 14 14 12 12 12 + DQT, Row #2: 13 16 14 14 12 12 12 12 + DQT, Row #3: 24 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 90.19 (scaling=19.62 variance=201.04) + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x00000326 + Length = 4 + interval = 115 + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x0000032C + Length = 14 + DCTEncodeVersion = 100 + APP14Flags0 = 49152 + APP14Flags1 = 0 + ColorTransform = 1 [YCbCr] + +*** Marker: SOF1 (Extended Sequential DCT, Huffman) (xFFC1) *** + OFFSET: 0x0000033C + Frame header length = 17 + Precision = 8 + Number of Lines = 496 + Samples per Line = 920 + Image Size = 920 x 496 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000034F + Huffman table length = 626 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 05 + Codes of length 03 bits (005 total): 02 03 04 06 07 + Codes of length 04 bits (001 total): 01 + Codes of length 05 bits (001 total): 08 + Codes of length 06 bits (001 total): 00 + Codes of length 07 bits (000 total): + Codes of length 08 bits (003 total): 09 0A 0B + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 02 03 + Codes of length 03 bits (003 total): 01 04 05 + Codes of length 04 bits (001 total): 00 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (000 total): + Codes of length 07 bits (002 total): 07 08 + Codes of length 08 bits (003 total): 09 0A 0B + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 2 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (003 total): 00 03 04 + Codes of length 04 bits (001 total): 05 + Codes of length 05 bits (000 total): + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (005 total): 07 08 09 0A 0B + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (002 total): 03 11 + Codes of length 04 bits (002 total): 04 12 + Codes of length 05 bits (001 total): 21 + Codes of length 06 bits (003 total): 00 05 13 + Codes of length 07 bits (002 total): 22 31 + Codes of length 08 bits (004 total): 06 14 32 41 + Codes of length 09 bits (002 total): 23 51 + Codes of length 10 bits (003 total): 15 42 61 + Codes of length 11 bits (005 total): 07 16 33 52 71 + Codes of length 12 bits (006 total): 24 43 62 81 91 F0 + Codes of length 13 bits (006 total): 25 34 72 A1 B1 C1 + Codes of length 14 bits (012 total): 08 18 26 46 53 63 82 92 93 D1 D2 F1 + Codes of length 15 bits (111 total): 09 0A 17 19 1A 27 28 29 2A 35 36 37 38 39 3A 44 + 45 47 48 49 4A 54 55 56 57 58 59 5A 64 65 66 67 + 68 69 6A 73 74 75 76 77 78 79 7A 83 84 85 86 87 + 88 89 8A 94 95 96 97 98 99 9A A2 A3 A4 A5 A6 A7 + A8 A9 AA B2 B3 B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 + C6 C7 C8 C9 CA D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 + E4 E5 E6 E7 E8 E9 EA F2 F3 F4 F5 F6 F7 F8 F9 + Codes of length 16 bits (001 total): FA + Total number of codes: 162 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (003 total): 02 21 31 + Codes of length 05 bits (004 total): 41 51 61 F0 + Codes of length 06 bits (006 total): 03 12 13 71 81 91 + Codes of length 07 bits (006 total): 14 A1 B1 C1 D1 E1 + Codes of length 08 bits (002 total): 04 F1 + Codes of length 09 bits (002 total): 22 32 + Codes of length 10 bits (002 total): 52 62 + Codes of length 11 bits (004 total): 05 42 72 A2 + Codes of length 12 bits (125 total): 06 07 08 09 0A 15 16 17 18 19 1A 23 24 25 26 27 + 28 29 2A 33 34 35 36 37 38 39 3A 43 44 45 46 47 + 48 49 4A 53 54 55 56 57 58 59 5A 63 64 65 66 67 + 68 69 6A 73 74 75 76 77 78 79 7A 82 83 84 85 86 + 87 88 89 8A 92 93 94 95 96 97 98 99 9A A3 A4 A5 + A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 B8 B9 BA C2 C3 + C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 D6 D7 D8 D9 DA + E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 F4 F5 + Codes of length 13 bits (005 total): F6 F7 F8 F9 FA + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 162 + + ---- + Destination ID = 2 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (001 total): 02 + Codes of length 05 bits (005 total): 12 21 31 41 51 + Codes of length 06 bits (004 total): 03 61 71 F0 + Codes of length 07 bits (004 total): 13 81 91 A1 + Codes of length 08 bits (006 total): 04 14 C1 D1 E1 F1 + Codes of length 09 bits (002 total): 22 B1 + Codes of length 10 bits (001 total): 42 + Codes of length 11 bits (004 total): 32 52 92 D2 + Codes of length 12 bits (131 total): 05 06 07 08 09 0A 15 16 17 18 19 1A 23 24 25 26 + 27 28 29 2A 33 34 35 36 37 38 39 3A 43 44 45 46 + 47 48 49 4A 53 54 55 56 57 58 59 5A 62 63 64 65 + 66 67 68 69 6A 72 73 74 75 76 77 78 79 7A 82 83 + 84 85 86 87 88 89 8A 93 94 95 96 97 98 99 9A A2 + A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 B8 B9 + BA C2 C3 C4 C5 C6 C7 C8 C9 CA D3 D4 D5 D6 D7 D8 + D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 F4 F5 F6 + F7 F8 F9 + Codes of length 13 bits (001 total): FA + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000005C3 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=2(DC),2(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000005D1 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0003ED77.0 + + Compression stats: + Compression Ratio: 5.35:1 + Bits per pixel: 4.49:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 1109 ( 16%) + # codes of length 03 bits: 4934 ( 69%) + # codes of length 04 bits: 705 ( 10%) + # codes of length 05 bits: 22 ( 0%) + # codes of length 06 bits: 360 ( 5%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2599 ( 36%) + # codes of length 03 bits: 2938 ( 41%) + # codes of length 04 bits: 1592 ( 22%) + # codes of length 05 bits: 1 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 2, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 3838 ( 54%) + # codes of length 03 bits: 3132 ( 44%) + # codes of length 04 bits: 156 ( 2%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 4 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 170962 ( 54%) + # codes of length 03 bits: 67518 ( 21%) + # codes of length 04 bits: 33616 ( 11%) + # codes of length 05 bits: 9306 ( 3%) + # codes of length 06 bits: 15458 ( 5%) + # codes of length 07 bits: 7462 ( 2%) + # codes of length 08 bits: 6393 ( 2%) + # codes of length 09 bits: 1640 ( 1%) + # codes of length 10 bits: 1220 ( 0%) + # codes of length 11 bits: 975 ( 0%) + # codes of length 12 bits: 581 ( 0%) + # codes of length 13 bits: 213 ( 0%) + # codes of length 14 bits: 134 ( 0%) + # codes of length 15 bits: 75 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 11236 ( 26%) + # codes of length 03 bits: 12123 ( 28%) + # codes of length 04 bits: 7424 ( 17%) + # codes of length 05 bits: 5864 ( 13%) + # codes of length 06 bits: 4420 ( 10%) + # codes of length 07 bits: 1997 ( 5%) + # codes of length 08 bits: 545 ( 1%) + # codes of length 09 bits: 244 ( 1%) + # codes of length 10 bits: 61 ( 0%) + # codes of length 11 bits: 41 ( 0%) + # codes of length 12 bits: 31 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 2, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 15434 ( 46%) + # codes of length 03 bits: 3540 ( 11%) + # codes of length 04 bits: 2524 ( 8%) + # codes of length 05 bits: 5638 ( 17%) + # codes of length 06 bits: 3224 ( 10%) + # codes of length 07 bits: 1556 ( 5%) + # codes of length 08 bits: 1170 ( 3%) + # codes of length 09 bits: 277 ( 1%) + # codes of length 10 bits: 14 ( 0%) + # codes of length 11 bits: 111 ( 0%) + # codes of length 12 bits: 34 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[ 97] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 762, 70, -70] RGB=[210,226,237] @ MCU[ 56, 4] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 61 + Next position in scan buffer: Offset 0x0003ED76.3 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0003ED77 + + +*** Searching Compression Signatures *** + + Signature: 01180AF3DE63318828A86409EF4013DD + Signature (Rotated): 01180AF3DE63318828A86409EF4013DD + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[Adobe Photoshop ] [Save As 08 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue517-No-EOI-Progressive.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue517-No-EOI-Progressive.jpg.txt new file mode 100644 index 0000000000..47e77a4f41 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue517-No-EOI-Progressive.jpg.txt @@ -0,0 +1,406 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue517-No-EOI-Progressive.jpg] + Filesize: [2192567] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 500 x 500 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 248 + Identifier = [Exif] + Identifier TIFF = 0x[4D4D002A 00000008] + Endian = Motorola (big) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0007 + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 500/1 + [YResolution ] = 500/1 + [ResolutionUnit ] = Inch + [Software ] = "Adobe Photoshop CS6 (Macintosh)" + [DateTime ] = "2018:01:06 12:59:23" + [ExifOffset ] = @ 0x00A6 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000C4 + Dir Length = 0x0004 + [DateTimeDigitized ] = "2018:01:06 04:40:19" + [ColorSpace ] = sRGB + [ExifImageWidth ] = 0x[000008CA] / 2250 + [ExifImageHeight ] = 0x[000008CA] / 2250 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x0000010E + Length = 4875 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x0000141B + Length = 100 + Identifier = [Photoshop 3.0] + 8BIM: [0x0404] Name="" Len=[0x002C] DefinedName="IPTC-NAA record" + IPTC [001:090] Coded Character Set = "%G" + IPTC [002:000] Record Version = 2 + IPTC [002:062] Digital Creation Date = "20180106" + IPTC [002:063] Digital Creation Time = "044019-0500" + 8BIM: [0x0425] Name="" Len=[0x0010] DefinedName="Caption digest" + Caption digest = | 0x5D 51 F3 F0 D0 DE FC 5F 94 67 16 6F B1 02 A3 89 | ]Q....._.g.o.... + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x00001481 + Frame header length = 17 + Precision = 8 + Number of Lines = 2250 + Samples per Line = 2250 + Image Size = 2250 x 2250 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00001494 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 03 + Codes of length 03 bits (005 total): 02 04 01 05 00 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000014B5 + Huffman table length = 195 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 02 00 03 + Codes of length 04 bits (003 total): 11 04 12 + Codes of length 05 bits (002 total): 21 05 + Codes of length 06 bits (004 total): 31 13 22 10 + Codes of length 07 bits (003 total): 06 41 51 + Codes of length 08 bits (004 total): 32 14 61 71 + Codes of length 09 bits (006 total): 23 07 81 20 91 42 + Codes of length 10 bits (004 total): 15 A1 52 33 + Codes of length 11 bits (007 total): B1 24 62 30 16 C1 72 + Codes of length 12 bits (006 total): D1 43 92 34 82 08 + Codes of length 13 bits (004 total): E1 53 40 25 + Codes of length 14 bits (008 total): 63 17 35 F0 93 73 A2 50 + Codes of length 15 bits (006 total): 44 B2 83 F1 26 54 + Codes of length 16 bits (115 total): 36 64 94 74 C2 60 D2 84 A3 18 70 E2 27 45 37 65 + B3 55 75 A4 95 C3 85 F2 D3 46 76 80 E3 47 56 66 + B4 09 0A 19 1A 28 29 2A 38 39 3A 48 49 4A 57 58 + 59 5A 67 68 69 6A 77 78 79 7A 86 87 88 89 8A 90 + 96 97 98 99 9A A0 A5 A6 A7 A8 A9 AA B0 B5 B6 B7 + B8 B9 BA C0 C4 C5 C6 C7 C8 C9 CA D0 D4 D5 D6 D7 + D8 D9 DA E0 E4 E5 E6 E7 E8 E9 EA F3 F4 F5 F6 F7 + F8 F9 FA + Total number of codes: 176 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000157A + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 01 02 00 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000159B + Huffman table length = 195 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 00 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (003 total): 10 12 21 + Codes of length 06 bits (003 total): 04 20 31 + Codes of length 07 bits (003 total): 41 13 05 + Codes of length 08 bits (002 total): 30 22 + Codes of length 09 bits (003 total): 32 51 14 + Codes of length 10 bits (005 total): 40 06 33 23 61 + Codes of length 11 bits (002 total): 42 15 + Codes of length 12 bits (005 total): 71 52 34 81 50 + Codes of length 13 bits (002 total): 24 91 + Codes of length 14 bits (004 total): A1 43 B1 16 + Codes of length 15 bits (004 total): 07 62 35 53 + Codes of length 16 bits (135 total): F0 D1 25 60 C1 44 E1 72 F1 17 82 63 36 70 26 45 + 54 92 27 A2 D2 08 09 0A 18 19 1A 28 29 2A 37 38 + 39 3A 46 47 48 49 4A 55 56 57 58 59 5A 64 65 66 + 67 68 69 6A 73 74 75 76 77 78 79 7A 80 83 84 85 + 86 87 88 89 8A 90 93 94 95 96 97 98 99 9A A0 A3 + A4 A5 A6 A7 A8 A9 AA B0 B2 B3 B4 B5 B6 B7 B8 B9 + BA C0 C2 C3 C4 C5 C6 C7 C8 C9 CA D0 D3 D4 D5 D6 + D7 D8 D9 DA E0 E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 176 + + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00001660 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 1 1 2 + DQT, Row #1: 1 1 1 1 1 1 1 2 + DQT, Row #2: 1 1 1 1 1 1 2 2 + DQT, Row #3: 1 1 1 1 1 2 2 3 + DQT, Row #4: 1 1 1 1 2 2 3 3 + DQT, Row #5: 1 1 1 2 2 3 3 3 + DQT, Row #6: 1 1 2 2 3 3 3 3 + DQT, Row #7: 2 2 2 3 3 3 3 3 + Approx quality factor = 98.11 (scaling=3.79 variance=4.10) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000016A5 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 1 1 1 2 3 3 3 3 + DQT, Row #1: 1 1 1 2 3 3 3 3 + DQT, Row #2: 1 1 2 3 3 3 3 3 + DQT, Row #3: 2 2 3 3 3 3 3 3 + DQT, Row #4: 3 3 3 3 3 3 3 3 + DQT, Row #5: 3 3 3 3 3 3 3 3 + DQT, Row #6: 3 3 3 3 3 3 3 3 + DQT, Row #7: 3 3 3 3 3 3 3 3 + Approx quality factor = 98.36 (scaling=3.29 variance=0.42) + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000016EA + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00023AAF + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0003E82C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0006B107 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0008AA32 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000BA727 + Huffman table length = 51 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (003 total): 11 00 21 + Codes of length 04 bits (000 total): + Codes of length 05 bits (002 total): 31 41 + Codes of length 06 bits (002 total): 51 61 + Codes of length 07 bits (002 total): 71 81 + Codes of length 08 bits (002 total): 91 A1 + Codes of length 09 bits (002 total): B1 C1 + Codes of length 10 bits (003 total): F0 D1 10 + Codes of length 11 bits (001 total): E1 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (002 total): 20 30 + Codes of length 16 bits (011 total): 40 50 60 70 80 90 A0 B0 C0 D0 E0 + Total number of codes: 032 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000BA75C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000FE1E7 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x001056B6 + Huffman table length = 51 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (000 total): + Codes of length 05 bits (003 total): 21 31 10 + Codes of length 06 bits (000 total): + Codes of length 07 bits (001 total): 41 + Codes of length 08 bits (002 total): 51 61 + Codes of length 09 bits (005 total): 20 71 F0 91 81 + Codes of length 10 bits (005 total): A1 B1 D1 C1 E1 + Codes of length 11 bits (001 total): F1 + Codes of length 12 bits (001 total): 30 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): 40 + Codes of length 15 bits (001 total): 50 + Codes of length 16 bits (009 total): 60 70 80 90 A0 B0 C0 D0 E0 + Total number of codes: 032 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x001056EB + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0014E060 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x001879C8 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x002174B5 + + +*** Searching Compression Signatures *** + + Signature: 01DADDC4908E9BA57CC067EEAD54E67D + Signature (Rotated): 01DADDC4908E9BA57CC067EEAD54E67D + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: OK [Adobe Photoshop CS6 (Macintosh)] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[Adobe Photoshop ] [Save As 12 ] + + NOTE: EXIF Software field recognized as from editor + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue518-Bad-RST-Progressive.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue518-Bad-RST-Progressive.jpg.txt new file mode 100644 index 0000000000..1b1027f273 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue518-Bad-RST-Progressive.jpg.txt @@ -0,0 +1,759 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue518-Bad-RST-Progressive.jpg] + Filesize: [3764739] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 300 x 300 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 14215 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0009 + [Make ] = "OLYMPUS CORPORATION" + [Model ] = "E-1" + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 300/1 + [YResolution ] = 300/1 + [ResolutionUnit ] = Inch + [Software ] = "GIMP 2.8.10" + [DateTime ] = "2017:04:18 16:37:56" + [ExifOffset ] = @ 0x00BE + Offset to Next IFD = 0x000001DC + + EXIF IFD1 @ Absolute 0x000001FA + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x023A = @ 0x0258 + [JpegIFByteCount ] = 0x[00003545] / 13637 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000DC + Dir Length = 0x0011 + [ExposureTime ] = 1/4 s + [FNumber ] = F18.0 + [ExposureProgram ] = Manual + [ISOSpeedRatings ] = 100 + [ExifVersion ] = 02.21 + [DateTimeOriginal ] = "2005:07:20 20:08:42" + [ShutterSpeedValue ] = 2/1 + [ApertureValue ] = 833985/100000 + [ExposureBiasValue ] = 0.00 eV + [MaxApertureValue ] = 2972656/1000000 + [MeteringMode ] = CenterWeightedAverage + [Flash ] = Flash did not fire + [FocalLength ] = 14 mm + [FlashPixVersion ] = 01.00 + [ColorSpace ] = Uncalibrated + [ExifImageWidth ] = 0x[00000BB8] / 3000 + [ExifImageHeight ] = 0x[00000BB8] / 3000 + +*** Marker: COM (Comment) (xFFFE) *** + OFFSET: 0x0000379D + Comment length = 3 + Comment= + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x000037A2 + Length = 5091 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + | + | + | + | + | 3.1 + | _7201666.ORF + | Custom + | 7450 + | -7 + | -0.75 + | True + | 4 + | True + | 100 + | True + | 0 + | 0 + | 25 + | 0 + | 25 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | Medium Contrast + | ACR 2.4 + | True + | False + | True + | + | + | 0, 0 + | 32, 22 + | 64, 56 + | 128, 128 + | 192, 196 + | 255, 255 + | + | + | 3.1 + | _7201666.ORF + | Custom + | 7450 + | -7 + | -0.75 + | True + | 4 + | True + | 100 + | True + | 0 + | 0 + | 25 + | 0 + | 25 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | Medium Contrast + | ACR 2.4 + | True + | False + | True + | + | + | 0, 0 + | 32, 22 + | 64, 56 + | 128, 128 + | 192, 196 + | 255, 255 + | + | + | + | + | 0 + | Adobe Photoshop CS6 (Macintosh) + | 0 + | 2014-06-09T12:43:59-04:00 + | 2005-07-21T18:39:06-06:00 + | 2014-06-09T12:43:59-04:00 + | + | + | xmp.iid:0A801174072068118083C9374AAA53C2 + | uuid:021303F2FBA711D98B5DCD54C315AFD0 + | + | xmp.iid:0A801174072068118083C9374AAA53C2 + | uuid:021303F2FBA711D98B5DCD54C315AFD0 + | + | + | + | + | + | + | + | + | image/jpeg + | + | + | 2005-07-20T20:08:42 + | A8D68AA81537D1C7170A5C69A46C6C94 + | 3 + | Adobe RGB (1998) + | + | + | 100 + | + | + | + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00004B87 + Length = 3160 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 3144 bytes + Preferred CMM Type : 'Lino' (0x4C696E6F) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 1998-02-09 06:49:00 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Microsoft Corporation ('MSFT' (0x4D534654)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : 'IEC ' (0x49454320) + Device Model : 'sRGB' (0x73524742) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'HP ' (0x48502020) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000057E1 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 5 8 10 12 + DQT, Row #1: 2 2 3 4 5 12 12 11 + DQT, Row #2: 3 3 3 5 8 11 14 11 + DQT, Row #3: 3 3 4 6 10 17 16 12 + DQT, Row #4: 4 4 7 11 14 22 21 15 + DQT, Row #5: 5 7 11 13 16 21 23 18 + DQT, Row #6: 10 13 16 17 21 24 24 20 + DQT, Row #7: 14 18 19 20 22 20 21 20 + Approx quality factor = 90.06 (scaling=19.88 variance=1.14) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00005826 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 3 4 5 9 20 20 20 20 + DQT, Row #1: 4 4 5 13 20 20 20 20 + DQT, Row #2: 5 5 11 20 20 20 20 20 + DQT, Row #3: 9 13 20 20 20 20 20 20 + DQT, Row #4: 20 20 20 20 20 20 20 20 + DQT, Row #5: 20 20 20 20 20 20 20 20 + DQT, Row #6: 20 20 20 20 20 20 20 20 + DQT, Row #7: 20 20 20 20 20 20 20 20 + Approx quality factor = 89.93 (scaling=20.14 variance=0.34) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000586B + Frame header length = 17 + Precision = 8 + Number of Lines = 3000 + Samples per Line = 3000 + Image Size = 3000 x 3000 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000587E + Huffman table length = 28 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 04 05 + Codes of length 03 bits (002 total): 03 06 + Codes of length 04 bits (003 total): 00 01 02 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000589C + Huffman table length = 27 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 01 02 03 + Codes of length 03 bits (001 total): 00 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x000058B9 + Length = 4 + interval = 375 + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000058BF + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0004A3DA + Huffman table length = 55 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 02 03 + Codes of length 03 bits (003 total): 01 04 05 + Codes of length 04 bits (000 total): + Codes of length 05 bits (001 total): 00 + Codes of length 06 bits (004 total): 06 11 12 13 + Codes of length 07 bits (001 total): 14 + Codes of length 08 bits (003 total): 15 21 22 + Codes of length 09 bits (003 total): 10 23 31 + Codes of length 10 bits (004 total): 07 20 24 41 + Codes of length 11 bits (002 total): 16 32 + Codes of length 12 bits (002 total): 30 33 + Codes of length 13 bits (002 total): 25 40 + Codes of length 14 bits (002 total): 17 42 + Codes of length 15 bits (000 total): + Codes of length 16 bits (007 total): 34 50 60 43 26 35 44 + Total number of codes: 036 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0004A413 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000B0746 + Huffman table length = 62 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (004 total): 03 10 12 31 + Codes of length 06 bits (001 total): 41 + Codes of length 07 bits (004 total): 13 20 22 51 + Codes of length 08 bits (002 total): 04 32 + Codes of length 09 bits (001 total): 61 + Codes of length 10 bits (003 total): 14 30 71 + Codes of length 11 bits (003 total): 23 40 42 + Codes of length 12 bits (003 total): 33 50 52 + Codes of length 13 bits (003 total): 05 81 91 + Codes of length 14 bits (003 total): 60 A1 B1 + Codes of length 15 bits (000 total): + Codes of length 16 bits (011 total): 15 24 62 43 53 C1 D1 72 F0 F1 E1 + Total number of codes: 043 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000B0786 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000E3DFE + Huffman table length = 69 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (002 total): 03 21 + Codes of length 05 bits (002 total): 12 31 + Codes of length 06 bits (000 total): + Codes of length 07 bits (006 total): 04 10 13 22 41 51 + Codes of length 08 bits (001 total): 32 + Codes of length 09 bits (002 total): 20 61 + Codes of length 10 bits (005 total): 05 14 23 42 71 + Codes of length 11 bits (002 total): 30 52 + Codes of length 12 bits (004 total): 33 40 81 91 + Codes of length 13 bits (005 total): 15 50 60 A1 B1 + Codes of length 14 bits (002 total): 62 F0 + Codes of length 15 bits (000 total): + Codes of length 16 bits (015 total): 24 43 70 C1 D1 06 53 72 E1 F1 25 34 44 63 A2 + Total number of codes: 050 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000E3E45 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0012926F + Huffman table length = 79 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 00 02 03 + Codes of length 04 bits (002 total): 11 12 + Codes of length 05 bits (005 total): 04 13 21 31 41 + Codes of length 06 bits (003 total): 22 32 51 + Codes of length 07 bits (003 total): 23 42 61 + Codes of length 08 bits (002 total): 05 14 + Codes of length 09 bits (003 total): 33 52 71 + Codes of length 10 bits (007 total): 10 24 43 62 81 91 A1 + Codes of length 11 bits (001 total): B1 + Codes of length 12 bits (006 total): 15 20 30 53 72 C1 + Codes of length 13 bits (004 total): 34 40 50 82 + Codes of length 14 bits (003 total): 60 63 92 + Codes of length 15 bits (002 total): A2 D1 + Codes of length 16 bits (015 total): 25 44 70 E1 F0 73 83 B2 F1 06 54 16 35 C2 74 + Total number of codes: 060 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x001292C0 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x001CCECE + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (003 total): 41 51 61 + Codes of length 06 bits (000 total): + Codes of length 07 bits (002 total): 71 81 + Codes of length 08 bits (002 total): 91 A1 + Codes of length 09 bits (002 total): 10 B1 + Codes of length 10 bits (002 total): C1 D1 + Codes of length 11 bits (003 total): 20 E1 F0 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (001 total): 30 + Codes of length 14 bits (001 total): 40 + Codes of length 15 bits (001 total): 50 + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x001CCEFA + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0024E532 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0025B81A + Huffman table length = 42 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (001 total): 31 + Codes of length 06 bits (001 total): 41 + Codes of length 07 bits (000 total): + Codes of length 08 bits (002 total): 10 51 + Codes of length 09 bits (002 total): 61 71 + Codes of length 10 bits (001 total): 81 + Codes of length 11 bits (003 total): 20 91 A1 + Codes of length 12 bits (005 total): 30 B1 C1 D1 F0 + Codes of length 13 bits (001 total): E1 + Codes of length 14 bits (001 total): 40 + Codes of length 15 bits (001 total): F1 + Codes of length 16 bits (001 total): 50 + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0025B846 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0029943F + Huffman table length = 43 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (001 total): 31 + Codes of length 06 bits (000 total): + Codes of length 07 bits (002 total): 41 51 + Codes of length 08 bits (002 total): 10 61 + Codes of length 09 bits (001 total): 71 + Codes of length 10 bits (003 total): 81 91 A1 + Codes of length 11 bits (005 total): 20 B1 C1 D1 F0 + Codes of length 12 bits (001 total): E1 + Codes of length 13 bits (001 total): 30 + Codes of length 14 bits (001 total): F1 + Codes of length 15 bits (000 total): + Codes of length 16 bits (003 total): 40 50 60 + Total number of codes: 024 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0029946C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x002E23F1 + Huffman table length = 41 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (003 total): 41 51 61 + Codes of length 06 bits (001 total): 71 + Codes of length 07 bits (000 total): + Codes of length 08 bits (002 total): 81 91 + Codes of length 09 bits (002 total): A1 B1 + Codes of length 10 bits (002 total): C1 D1 + Codes of length 11 bits (003 total): 10 E1 F0 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (001 total): 20 + Codes of length 14 bits (001 total): 30 + Codes of length 15 bits (001 total): 40 + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x002E241C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00397201 + + +*** Embedded JPEG Thumbnail *** + Offset: 0x00000258 + Length: 0x00003545 (13637) + + * Embedded Thumb Marker: SOI + + * Embedded Thumb Marker: APP0 + Length = 16 + + * Embedded Thumb Marker: DQT + Length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance, typically) + DQT, Row #0: 8 6 5 8 12 20 26 31 + DQT, Row #1: 6 6 7 10 13 29 30 28 + DQT, Row #2: 7 7 8 12 20 29 35 28 + DQT, Row #3: 7 9 11 15 26 44 40 31 + DQT, Row #4: 9 11 19 28 34 55 52 39 + DQT, Row #5: 12 18 28 32 41 52 57 46 + DQT, Row #6: 25 32 39 44 52 61 60 51 + DQT, Row #7: 36 46 48 49 56 50 52 50 + + * Embedded Thumb Marker: DQT + Length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance, typically) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + + * Embedded Thumb Marker: SOF + Frame header length = 17 + Precision = 8 + Number of Lines = 196 + Samples per Line = 196 + Image Size = 196 x 196 + + * Embedded Thumb Marker: DHT + Length = 31 + + * Embedded Thumb Marker: DHT + Length = 181 + + * Embedded Thumb Marker: DHT + Length = 31 + + * Embedded Thumb Marker: DHT + Length = 181 + + * Embedded Thumb Marker: SOS + Skipping scan data + Skipped 13024 bytes + + * Embedded Thumb Marker: EOI + + * Embedded Thumb Signature: 0182408A81A4ABF04D4A34A8A5E98C58 + +*** Searching Compression Signatures *** + + Signature: 013BA18D5561625796E986FDBC09F846 + Signature (Rotated): 01AC57E12793DFA7C46C704625C5AF0F + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: OK [OLYMPUS CORPORATION] [E-1] + EXIF Makernotes: NONE + EXIF Software: OK [GIMP 2.8.10] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[??? ] [Treo 680 ] [ ] No + CAM:[Canon ] [Canon PowerShot Pro1 ] [fine ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E3100 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5000 ] [FINE ] No + CAM:[NIKON ] [E5700 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[NIKON ] [E885 ] [FINE ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 9530 ] [Superfine ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-W1 ] [ ] No + CAM:[SONY ] [SONY ] [ ] No + SW :[ACDSee ] [ ] + SW :[FixFoto ] [fine ] + SW :[IJG Library ] [090 ] + SW :[ZoomBrowser EX ] [high ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [090 ] + SW :[IrfanView ] [090 ] + SW :[idImager ] [090 ] + SW :[FastStone Image Viewer ] [090 ] + SW :[NeatImage ] [090 ] + SW :[Paint.NET ] [090 ] + SW :[Photomatix ] [090 ] + SW :[XnView ] [090 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 2 - Image has high probability of being processed/edited + + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue520-InvalidCast.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue520-InvalidCast.jpg.txt new file mode 100644 index 0000000000..aadf150e6d --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue520-InvalidCast.jpg.txt @@ -0,0 +1,364 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue520-InvalidCast.jpg] + Filesize: [7751] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 499 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0011 + [DateTime ] = "2017:09:06 15:13:32" + [Model ] = "SAMSUNG-SM-J320AZ" + [Orientation ] = 1 = Row 0: top, Col 0: left + [WhiteBalance ] = Auto white balance + [DateTime ] = "2017:09:06 15:13:04" + [Make ] = "samsung" + [GPSOffset ] = @ 0x0124 + [ExifOffset ] = @ 0x01CD + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000001EB + Dir Length = 0x0002 + + EXIF GPSIFD @ Absolute 0x00000142 + Dir Length = 0x0008 + [GPSTimeStamp ] = 115:8:12.00 + [GPSLatitudeRef ] = "N" + [GPSLongitude ] = 115 deg 8' 12.000" + [GPSLongitudeRef ] = "W" + [GPSDateStamp ] = "2017:08:08" + [GPSLatitude ] = 36 deg 11' 18.000" + [GPSAltitudeRef ] = Below Sea Level + [GPSAltitude ] = 0.000 m + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000209 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 2 2 1 + DQT, Row #4: 1 1 1 1 1 2 2 2 + DQT, Row #5: 1 1 1 1 2 2 2 2 + DQT, Row #6: 1 1 2 2 2 2 2 2 + DQT, Row #7: 1 2 2 2 2 2 2 2 + Approx quality factor = 98.32 (scaling=3.35 variance=5.00) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0000024E + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 1 1 1 1 2 2 2 2 + DQT, Row #1: 1 1 1 1 2 2 2 2 + DQT, Row #2: 1 1 1 2 2 2 2 2 + DQT, Row #3: 1 1 2 2 2 2 2 2 + DQT, Row #4: 2 2 2 2 2 2 2 2 + DQT, Row #5: 2 2 2 2 2 2 2 2 + DQT, Row #6: 2 2 2 2 2 2 2 2 + DQT, Row #7: 2 2 2 2 2 2 2 2 + Approx quality factor = 98.83 (scaling=2.34 variance=0.89) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00000293 + Frame header length = 17 + Precision = 8 + Number of Lines = 100 + Samples per Line = 100 + Image Size = 100 x 100 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000002A6 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 0A + Codes of length 03 bits (001 total): 09 + Codes of length 04 bits (004 total): 06 07 08 0B + Codes of length 05 bits (003 total): 03 04 05 + Codes of length 06 bits (001 total): 01 + Codes of length 07 bits (001 total): 02 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000002C7 + Huffman table length = 60 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (004 total): 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (003 total): 00 07 11 + Codes of length 06 bits (003 total): 08 12 13 + Codes of length 07 bits (002 total): 14 21 + Codes of length 08 bits (003 total): 09 22 31 + Codes of length 09 bits (005 total): 0A 15 41 51 61 + Codes of length 10 bits (006 total): 16 23 24 32 33 71 + Codes of length 11 bits (003 total): 17 52 62 + Codes of length 12 bits (009 total): 18 42 54 73 91 93 A3 B1 B2 + Codes of length 13 bits (001 total): D2 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 041 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000305 + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 03 04 05 06 07 + Codes of length 04 bits (001 total): 08 + Codes of length 05 bits (001 total): 02 + Codes of length 06 bits (001 total): 01 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000323 + Huffman table length = 50 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 04 05 11 + Codes of length 05 bits (003 total): 00 12 21 + Codes of length 06 bits (003 total): 06 22 31 + Codes of length 07 bits (003 total): 13 41 51 + Codes of length 08 bits (002 total): 61 71 + Codes of length 09 bits (004 total): 07 14 32 91 + Codes of length 10 bits (005 total): 15 23 42 81 D1 + Codes of length 11 bits (005 total): 16 62 92 A1 B1 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 031 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000357 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00000365 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00001E45.0 + + Compression stats: + Compression Ratio: 4.36:1 + Bits per pixel: 5.50:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 97 ( 49%) + # codes of length 03 bits: 25 ( 13%) + # codes of length 04 bits: 51 ( 26%) + # codes of length 05 bits: 18 ( 9%) + # codes of length 06 bits: 3 ( 2%) + # codes of length 07 bits: 2 ( 1%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 26 ( 27%) + # codes of length 03 bits: 62 ( 63%) + # codes of length 04 bits: 5 ( 5%) + # codes of length 05 bits: 3 ( 3%) + # codes of length 06 bits: 2 ( 2%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 971 ( 16%) + # codes of length 03 bits: 3435 ( 57%) + # codes of length 04 bits: 456 ( 8%) + # codes of length 05 bits: 579 ( 10%) + # codes of length 06 bits: 285 ( 5%) + # codes of length 07 bits: 96 ( 2%) + # codes of length 08 bits: 74 ( 1%) + # codes of length 09 bits: 59 ( 1%) + # codes of length 10 bits: 30 ( 0%) + # codes of length 11 bits: 7 ( 0%) + # codes of length 12 bits: 9 ( 0%) + # codes of length 13 bits: 1 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 1143 ( 50%) + # codes of length 03 bits: 254 ( 11%) + # codes of length 04 bits: 445 ( 19%) + # codes of length 05 bits: 228 ( 10%) + # codes of length 06 bits: 111 ( 5%) + # codes of length 07 bits: 48 ( 2%) + # codes of length 08 bits: 20 ( 1%) + # codes of length 09 bits: 22 ( 1%) + # codes of length 10 bits: 13 ( 1%) + # codes of length 11 bits: 5 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[193] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1001, -7, 97] RGB=[255,244,251] @ MCU[ 5, 3] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00001E44.1 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00001E45 + + +*** Searching Compression Signatures *** + + Signature: 01C7F83908166C226C06A44017421732 + Signature (Rotated): 01D3EFDD3855C42AE3E0E6289F1A6726 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: OK [samsung] [SAMSUNG-SM-J320AZ] + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[Canon ] [Canon EOS-1Ds Mark II ] [fine ] No + CAM:[CASIO COMPUTER CO.,LTD. ] [EX-Z1000 ] [ ] Yes + CAM:[NIKON ] [NIKON D2X ] [FINE ] No + CAM:[NIKON ] [NIKON D3 ] [FINE ] No + CAM:[SIGMA ] [SIGMA SD10 ] [Qual:12 ] No + CAM:[SIGMA ] [SIGMA SD10 ] [Qual:12 ] No + CAM:[SIGMA ] [SIGMA SD14 ] [Qual:12 ] No + CAM:[SIGMA ] [SIGMA SD14 ] [Qual:12 ] No + CAM:[SONY ] [DSC-H2 ] [ ] No + CAM:[SONY ] [DSC-R1 ] [ ] No + CAM:[SONY ] [DSC-W7 ] [ ] No + SW :[Digital Photo Professiona] [09 ] + SW :[IJG Library ] [099 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [099 ] + SW :[IrfanView ] [099 ] + SW :[idImager ] [099 ] + SW :[FastStone Image Viewer ] [099 ] + SW :[NeatImage ] [099 ] + SW :[Paint.NET ] [099 ] + SW :[Photomatix ] [099 ] + SW :[XnView ] [099 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 2 - Image has high probability of being processed/edited + + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue624-DhtHasWrongLength-Progressive-N.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue624-DhtHasWrongLength-Progressive-N.jpg.txt new file mode 100644 index 0000000000..0ee1736d3c --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue624-DhtHasWrongLength-Progressive-N.jpg.txt @@ -0,0 +1,284 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue624-DhtHasWrongLength-Progressive-N.jpg] + Filesize: [30441] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 6 6 7 10 15 22 34 + DQT, Row #1: 6 7 8 11 14 16 21 30 + DQT, Row #2: 6 8 10 12 17 25 36 54 + DQT, Row #3: 7 11 12 16 21 30 42 62 + DQT, Row #4: 10 14 17 21 28 38 52 76 + DQT, Row #5: 15 16 25 30 38 50 68 95 + DQT, Row #6: 22 21 36 42 52 68 90 124 + DQT, Row #7: 34 30 54 62 76 95 124 167 + Approx quality factor = 71.19 (scaling=57.62 variance=593.35) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 6 6 6 7 10 15 22 34 + DQT, Row #1: 6 7 8 11 14 16 21 30 + DQT, Row #2: 6 8 10 12 17 25 36 54 + DQT, Row #3: 7 11 12 16 21 30 42 62 + DQT, Row #4: 10 14 17 21 28 38 52 76 + DQT, Row #5: 15 16 25 30 38 50 68 95 + DQT, Row #6: 22 21 36 42 52 68 90 124 + DQT, Row #7: 34 30 54 62 76 95 124 167 + Approx quality factor = 80.24 (scaling=39.51 variance=961.47) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009A + Frame header length = 17 + Precision = 8 + Number of Lines = 1080 + Samples per Line = 1080 + Image Size = 1080 x 1080 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000AD + Huffman table length = 51 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 05 06 + Codes of length 04 bits (003 total): 01 03 04 + Codes of length 05 bits (001 total): 02 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (003 total): 02 04 06 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 01 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 007 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000E2 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000151B + Huffman table length = 2 + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000151F + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000022BA + Huffman table length = 2 + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000022BE + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000309F + Huffman table length = 53 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 02 03 + Codes of length 04 bits (003 total): 00 04 20 + Codes of length 05 bits (007 total): 11 31 33 34 50 71 72 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (005 total): 12 21 52 60 61 + Codes of length 08 bits (007 total): 10 13 22 32 41 51 A1 + Codes of length 09 bits (003 total): 23 53 62 + Codes of length 10 bits (005 total): 70 80 81 A0 F1 + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 034 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000030D6 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003353 + Huffman table length = 54 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 02 04 + Codes of length 04 bits (002 total): 03 05 + Codes of length 05 bits (008 total): 00 06 20 32 50 63 71 B1 + Codes of length 06 bits (005 total): 11 25 31 35 73 + Codes of length 07 bits (002 total): 12 21 + Codes of length 08 bits (004 total): 10 22 51 60 + Codes of length 09 bits (005 total): 13 23 41 42 52 + Codes of length 10 bits (005 total): 14 33 70 80 A1 + Codes of length 11 bits (001 total): A0 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 035 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000338B + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000378D + Huffman table length = 83 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 02 03 04 + Codes of length 04 bits (001 total): 05 + Codes of length 05 bits (003 total): 06 07 11 + Codes of length 06 bits (005 total): 00 21 30 31 B2 + Codes of length 07 bits (009 total): 12 13 32 40 41 50 51 72 74 + Codes of length 08 bits (011 total): 14 16 22 33 35 42 52 61 71 B1 B3 + Codes of length 09 bits (009 total): 15 20 23 24 60 62 81 91 C2 + Codes of length 10 bits (006 total): 10 25 36 43 75 92 + Codes of length 11 bits (004 total): 82 93 A1 A2 + Codes of length 12 bits (006 total): 34 63 64 73 C3 D2 + Codes of length 13 bits (001 total): A3 + Codes of length 14 bits (005 total): 26 45 53 65 83 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 064 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000037E2 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x000076E7 + + +*** Searching Compression Signatures *** + + Signature: 014D6128740A2927C9914C433E852F5A + Signature (Rotated): 014D6128740A2927C9914C433E852F5A + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue694-Decode-Exif-OutOfRange.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue694-Decode-Exif-OutOfRange.jpg.txt new file mode 100644 index 0000000000..9feef52cce --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue694-Decode-Exif-OutOfRange.jpg.txt @@ -0,0 +1,368 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue694-Decode-Exif-OutOfRange.jpg] + Filesize: [226421] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000002 + Length = 194 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000014 + Dir Length = 0x0007 + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 96/1 + [YResolution ] = 96/1 + [ResolutionUnit ] = Inch + [Software ] = "PhotoFiltre 7" + [DateTime ] = "2017:08:30 22:45:26" + [ExifOffset ] = @ 0x0094 + Offset to Next IFD = 0xFC5019BC + + EXIF IFD1 @ Absolute 0xFC5019C8 + Dir Length = 0x0000 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000A0 + Dir Length = 0x0003 + [ExifVersion ] = 02.10 + [ExifImageWidth ] = 1400 + [ExifImageHeight ] = 1400 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000000C6 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 1 1 1 + DQT, Row #4: 1 1 1 1 1 1 1 1 + DQT, Row #5: 1 1 1 1 1 1 1 1 + DQT, Row #6: 1 1 1 1 1 1 1 1 + DQT, Row #7: 1 1 1 1 1 1 1 1 + Approx quality factor = 100.00 (scaling=2.99 variance=6.13) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0000010B + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 1 1 1 + DQT, Row #4: 1 1 1 1 1 1 1 1 + DQT, Row #5: 1 1 1 1 1 1 1 1 + DQT, Row #6: 1 1 1 1 1 1 1 1 + DQT, Row #7: 1 1 1 1 1 1 1 1 + Approx quality factor = 100.00 (scaling=1.54 variance=1.58) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00000150 + Frame header length = 17 + Precision = 8 + Number of Lines = 1400 + Samples per Line = 1400 + Image Size = 1400 x 1400 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000163 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000184 + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000023B + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000025C + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000313 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00000321 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00037473.0 + + Compression stats: + Compression Ratio: 26.06:1 + Bits per pixel: 0.92:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 25384 ( 82%) + # codes of length 03 bits: 1101 ( 4%) + # codes of length 04 bits: 566 ( 2%) + # codes of length 05 bits: 758 ( 2%) + # codes of length 06 bits: 429 ( 1%) + # codes of length 07 bits: 616 ( 2%) + # codes of length 08 bits: 933 ( 3%) + # codes of length 09 bits: 1189 ( 4%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 13762 ( 89%) + # codes of length 03 bits: 146 ( 1%) + # codes of length 04 bits: 264 ( 2%) + # codes of length 05 bits: 354 ( 2%) + # codes of length 06 bits: 509 ( 3%) + # codes of length 07 bits: 335 ( 2%) + # codes of length 08 bits: 116 ( 1%) + # codes of length 09 bits: 2 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 48125 ( 26%) + # codes of length 03 bits: 20074 ( 11%) + # codes of length 04 bits: 54692 ( 30%) + # codes of length 05 bits: 21145 ( 12%) + # codes of length 06 bits: 3017 ( 2%) + # codes of length 07 bits: 14358 ( 8%) + # codes of length 08 bits: 8803 ( 5%) + # codes of length 09 bits: 2231 ( 1%) + # codes of length 10 bits: 5065 ( 3%) + # codes of length 11 bits: 1096 ( 1%) + # codes of length 12 bits: 224 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 6 ( 0%) + # codes of length 16 bits: 4924 ( 3%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 25772 ( 49%) + # codes of length 03 bits: 5924 ( 11%) + # codes of length 04 bits: 7056 ( 13%) + # codes of length 05 bits: 6378 ( 12%) + # codes of length 06 bits: 2891 ( 5%) + # codes of length 07 bits: 1200 ( 2%) + # codes of length 08 bits: 1082 ( 2%) + # codes of length 09 bits: 1030 ( 2%) + # codes of length 10 bits: 559 ( 1%) + # codes of length 11 bits: 299 ( 1%) + # codes of length 12 bits: 38 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 73 ( 0%) + # codes of length 15 bits: 67 ( 0%) + # codes of length 16 bits: 260 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[ 57] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1016, 0, 0] RGB=[255,255,255] @ MCU[ 40, 2] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00037472.4 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00037473 + + +*** Searching Compression Signatures *** + + Signature: 01BBB1709AC9C1F89220D955A31A8F34 + Signature (Rotated): 01BBB1709AC9C1F89220D955A31A8F34 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: OK [PhotoFiltre 7] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[CASIO COMPUTER CO.,LTD ] [EX-Z750 ] [ ] Yes + CAM:[CASIO COMPUTER CO.,LTD. ] [EX-Z1000 ] [ ] Yes + CAM:[PENTAX ] [PENTAX Optio S5i ] [ ] Yes + CAM:[SIGMA ] [SIGMA SD9 ] [ ] Yes + SW :[ACDSee ] [100 ] + SW :[Apple ImageIO.framework ] [100 (Best) ] + SW :[Digital Photo Professiona] [10 ] + SW :[IJG Library ] [100 ] + SW :[MS Office Pic Mgr ] [ ] + SW :[Nikon Scan ] [Excellent Qualit] + SW :[Picasa ] [100 (Maximum) ] + SW :[ZoomBrowser EX ] [highest ] + SW :[EOS Viewer Utility ] [ ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [100 ] + SW :[IrfanView ] [100 ] + SW :[idImager ] [100 ] + SW :[FastStone Image Viewer ] [100 ] + SW :[NeatImage ] [100 ] + SW :[Paint.NET ] [100 ] + SW :[Photomatix ] [100 ] + SW :[XnView ] [100 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue695-Invalid-EOI.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue695-Invalid-EOI.jpg.txt new file mode 100644 index 0000000000..8911896afa --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue695-Invalid-EOI.jpg.txt @@ -0,0 +1,39 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue695-Invalid-EOI.jpg] + Filesize: [4805575] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 64 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0001 + [ExifOffset ] = @ 0x001A + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x00000038 + Dir Length = 0x0002 + [ExifImageWidth ] = 0x[000003E8] / 1000 + [ExifImageHeight ] = 0x[000003E8] / 1000 + +ERROR: Expected marker 0xFF, got 0x49 @ offset 0x00000056. Consider using [Tools->Img Search Fwd/Rev]. diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue696-Resize-Exif-OutOfRange.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue696-Resize-Exif-OutOfRange.jpg.txt new file mode 100644 index 0000000000..566291b47e --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue696-Resize-Exif-OutOfRange.jpg.txt @@ -0,0 +1,377 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue696-Resize-Exif-OutOfRange.jpg] + Filesize: [3196058] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 201 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0007 + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 96/1 + [YResolution ] = 96/1 + [ResolutionUnit ] = Inch + [Software ] = "PhotoFiltre Studio X" + [DateTime ] = "2017:09:12 23:47:30" + [ExifOffset ] = @ 0x009B + Offset to Next IFD = 0xFFFFFFFF + + EXIF IFD1 @ Absolute 0x0000001D + Dir Length = 0x4900 + Excessive # components (117440512). Limiting to first 4000. + Offset to Next IFD = 0x03011200 + + EXIF SubIFD @ Absolute 0x000000B9 + Dir Length = 0x0003 + [ExifVersion ] = 02.10 + [ExifImageWidth ] = 3000 + [ExifImageHeight ] = 3000 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000000DF + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 1 1 1 + DQT, Row #4: 1 1 1 1 1 1 1 1 + DQT, Row #5: 1 1 1 1 1 1 1 1 + DQT, Row #6: 1 1 1 1 1 1 1 1 + DQT, Row #7: 1 1 1 1 1 1 1 1 + Approx quality factor = 100.00 (scaling=2.99 variance=6.13) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000124 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 1 1 1 + DQT, Row #4: 1 1 1 1 1 1 1 1 + DQT, Row #5: 1 1 1 1 1 1 1 1 + DQT, Row #6: 1 1 1 1 1 1 1 1 + DQT, Row #7: 1 1 1 1 1 1 1 1 + Approx quality factor = 100.00 (scaling=1.54 variance=1.58) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00000169 + Frame header length = 17 + Precision = 8 + Number of Lines = 3000 + Samples per Line = 3000 + Image Size = 3000 x 3000 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000017C + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000019D + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000254 + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000275 + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000032C + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x0000033A + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0030C498.0 + + Compression stats: + Compression Ratio: 8.45:1 + Bits per pixel: 2.84:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 35306 ( 25%) + # codes of length 03 bits: 79378 ( 56%) + # codes of length 04 bits: 10642 ( 8%) + # codes of length 05 bits: 5371 ( 4%) + # codes of length 06 bits: 3913 ( 3%) + # codes of length 07 bits: 2829 ( 2%) + # codes of length 08 bits: 2486 ( 2%) + # codes of length 09 bits: 1451 ( 1%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 45165 ( 64%) + # codes of length 03 bits: 10069 ( 14%) + # codes of length 04 bits: 6960 ( 10%) + # codes of length 05 bits: 3541 ( 5%) + # codes of length 06 bits: 2100 ( 3%) + # codes of length 07 bits: 1345 ( 2%) + # codes of length 08 bits: 1100 ( 2%) + # codes of length 09 bits: 324 ( 0%) + # codes of length 10 bits: 84 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 1981662 ( 53%) + # codes of length 03 bits: 213036 ( 6%) + # codes of length 04 bits: 749857 ( 20%) + # codes of length 05 bits: 410362 ( 11%) + # codes of length 06 bits: 173055 ( 5%) + # codes of length 07 bits: 94282 ( 3%) + # codes of length 08 bits: 61648 ( 2%) + # codes of length 09 bits: 36705 ( 1%) + # codes of length 10 bits: 19723 ( 1%) + # codes of length 11 bits: 10118 ( 0%) + # codes of length 12 bits: 2157 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 211 ( 0%) + # codes of length 16 bits: 9772 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 425513 ( 38%) + # codes of length 03 bits: 127308 ( 11%) + # codes of length 04 bits: 204956 ( 18%) + # codes of length 05 bits: 171523 ( 15%) + # codes of length 06 bits: 89715 ( 8%) + # codes of length 07 bits: 30159 ( 3%) + # codes of length 08 bits: 25054 ( 2%) + # codes of length 09 bits: 22104 ( 2%) + # codes of length 10 bits: 10243 ( 1%) + # codes of length 11 bits: 4250 ( 0%) + # codes of length 12 bits: 210 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 1829 ( 0%) + # codes of length 15 bits: 1498 ( 0%) + # codes of length 16 bits: 2262 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[127] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 992, -112, 17] RGB=[254,255,227] @ MCU[ 35, 79] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x0030C497.3 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0030C498 + + +*** Searching Compression Signatures *** + + Signature: 01BBB1709AC9C1F89220D955A31A8F34 + Signature (Rotated): 01BBB1709AC9C1F89220D955A31A8F34 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: OK [PhotoFiltre Studio X] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[CASIO COMPUTER CO.,LTD ] [EX-Z750 ] [ ] Yes + CAM:[CASIO COMPUTER CO.,LTD. ] [EX-Z1000 ] [ ] Yes + CAM:[PENTAX ] [PENTAX Optio S5i ] [ ] Yes + CAM:[SIGMA ] [SIGMA SD9 ] [ ] Yes + SW :[ACDSee ] [100 ] + SW :[Apple ImageIO.framework ] [100 (Best) ] + SW :[Digital Photo Professiona] [10 ] + SW :[IJG Library ] [100 ] + SW :[MS Office Pic Mgr ] [ ] + SW :[Nikon Scan ] [Excellent Qualit] + SW :[Picasa ] [100 (Maximum) ] + SW :[ZoomBrowser EX ] [highest ] + SW :[EOS Viewer Utility ] [ ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [100 ] + SW :[IrfanView ] [100 ] + SW :[idImager ] [100 ] + SW :[FastStone Image Viewer ] [100 ] + SW :[NeatImage ] [100 ] + SW :[Paint.NET ] [100 ] + SW :[Photomatix ] [100 ] + SW :[XnView ] [100 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue721-InvalidAPP0.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue721-InvalidAPP0.jpg.txt new file mode 100644 index 0000000000..dc283bfcfc --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue721-InvalidAPP0.jpg.txt @@ -0,0 +1,446 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue721-InvalidAPP0.jpg] + Filesize: [1225163] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000002 + Length = 806 + Identifier = [Exif] + Identifier TIFF = 0x[4D4D002A 00000008] + Endian = Motorola (big) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000014 + Dir Length = 0x0007 + [Make ] = "NIKON CORPORATION" + [Model ] = "NIKON D300S" + [Software ] = "Adobe Bridge CS6 (Windows)" + [DateTime ] = "2017:06:07 16:49:51" + [Artist ] = ""Evgeniy Ivahiv Mr.Ivas"" + [Copyright ] = "Evgeniy Ivahiv Erich Krause" + [ExifOffset ] = @ 0x00EC + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000F8 + Dir Length = 0x0022 + [ExposureTime ] = 1/160 s + [FNumber ] = F10.0 + [ExposureProgram ] = Manual + [ISOSpeedRatings ] = 200 + [ExifVersion ] = 02.21 + [DateTimeOriginal ] = "2017:06:06 11:29:53" + [ShutterSpeedValue ] = 7321928/1000000 + [ApertureValue ] = 6643856/1000000 + [ExposureBiasValue ] = -3.00 eV + [MaxApertureValue ] = 50/10 + [MeteringMode ] = CenterWeightedAverage + [LightSource ] = unknown + [Flash ] = Flash did not fire + [FocalLength ] = 48 mm + [SubSecTimeOriginal ] = "24" + [ColorSpace ] = Uncalibrated + [ExifImageWidth ] = 2304 + [ExifImageHeight ] = 2998 + [SensingMethod ] = One-chip color area sensor + [FileSource ] = DSC + [SceneType ] = A directly photographed image + [ExposureMode ] = Manual exposure + [WhiteBalance ] = Manual white balance + [DigitalZoomRatio ] = 1/1 + [FocalLengthIn35mmFilm ] = 72 + [SceneCaptureType ] = Standard + [GainControl ] = 0 + [Contrast ] = 0 + [Saturation ] = 0 + [Sharpness ] = 2 + [SubjectDistanceRange ] = 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x0000032A + Length = 4442 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x00001486 + Length = 160 + Identifier = [Photoshop 3.0] + 8BIM: [0x0404] Name="" Len=[0x0068] DefinedName="IPTC-NAA record" + IPTC [001:090] Coded Character Set = "%G" + IPTC [002:000] Record Version = 4 + IPTC [002:055] Date Created = "20170606" + IPTC [002:060] Time Created = "112953" + IPTC [002:080] By-line = "Evgeniy Ivahiv Mr.Ivas" + IPTC [002:116] Copyright Notice = "Evgeniy Ivahiv Erich Krause" + 8BIM: [0x0425] Name="" Len=[0x0010] DefinedName="Caption digest" + Caption digest = | 0x59 13 63 D2 BD 08 14 B4 2B E3 4F 37 D7 52 D2 6F | Y.c.....+.O7.R.o + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00001528 + Length = 3160 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 3144 bytes + Preferred CMM Type : 'Lino' (0x4C696E6F) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 1998-02-09 06:49:00 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Microsoft Corporation ('MSFT' (0x4D534654)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : 'IEC ' (0x49454320) + Device Model : 'sRGB' (0x73524742) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'HP ' (0x48502020) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00002182 + Length = 12 + Identifier = [Adobe_CM] + Not known APP0 type. Skipping remainder. + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00002190 + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 7 11 14 17 22 17 + DQT, Row #1: 4 5 6 10 14 19 12 12 + DQT, Row #2: 7 6 8 14 19 12 12 12 + DQT, Row #3: 11 10 14 19 12 12 12 12 + DQT, Row #4: 14 14 19 12 12 12 12 12 + DQT, Row #5: 17 19 12 12 12 12 12 12 + DQT, Row #6: 22 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 83.88 (scaling=32.24 variance=430.71) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 7 9 19 34 20 20 17 17 + DQT, Row #1: 9 12 19 14 14 12 12 12 + DQT, Row #2: 19 19 14 14 12 12 12 12 + DQT, Row #3: 34 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 89.11 (scaling=21.78 variance=377.49) + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x00002216 + Length = 4 + interval = 288 + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x0000221C + Length = 14 + DCTEncodeVersion = 100 + APP14Flags0 = 49152 + APP14Flags1 = 0 + ColorTransform = 1 [YCbCr] + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000222C + Frame header length = 17 + Precision = 8 + Number of Lines = 2998 + Samples per Line = 2304 + Image Size = 2304 x 2998 + Raw Image Orientation = Portrait + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000223F + Huffman table length = 418 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (004 total): 03 04 05 06 + Codes of length 04 bits (003 total): 02 07 08 + Codes of length 05 bits (001 total): 01 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (001 total): 0A + Codes of length 08 bits (001 total): 0B + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (001 total): 06 + Codes of length 08 bits (000 total): + Codes of length 09 bits (002 total): 07 08 + Codes of length 10 bits (003 total): 09 0A 0B + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 02 03 11 + Codes of length 04 bits (002 total): 00 21 + Codes of length 05 bits (004 total): 04 12 31 41 + Codes of length 06 bits (002 total): 51 61 + Codes of length 07 bits (008 total): 05 13 22 71 81 91 A1 F0 + Codes of length 08 bits (004 total): 06 14 B1 C1 + Codes of length 09 bits (005 total): 23 32 D1 E1 F1 + Codes of length 10 bits (002 total): 07 42 + Codes of length 11 bits (003 total): 15 24 52 + Codes of length 12 bits (002 total): 33 62 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 16 + Codes of length 16 bits (125 total): 34 43 72 82 92 A2 08 17 53 B2 C2 25 D2 E2 44 83 + 84 F2 09 0A 18 19 1A 26 27 28 29 2A 35 36 37 38 + 39 3A 45 46 47 48 49 4A 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 85 + 86 87 88 89 8A 93 94 95 96 97 98 B3 C3 D3 99 9A + A3 A4 A5 A6 A7 A8 A9 AA B4 B5 B6 B7 B8 B9 BA C4 + C5 C6 C7 C8 C9 CA D4 D5 D6 D7 D8 D9 DA E3 E4 E5 + E6 E7 E8 E9 EA F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 02 11 + Codes of length 05 bits (001 total): 03 + Codes of length 06 bits (003 total): 12 21 31 + Codes of length 07 bits (001 total): 41 + Codes of length 08 bits (005 total): 04 13 51 61 71 + Codes of length 09 bits (002 total): 81 F0 + Codes of length 10 bits (006 total): 22 91 A1 B1 C1 D1 + Codes of length 11 bits (003 total): 14 32 E1 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (127 total): 05 06 07 08 09 0A 15 16 17 18 19 1A 23 24 25 26 + 27 28 29 2A 33 34 35 36 37 38 39 3A 42 43 44 45 + 46 47 48 49 4A 52 53 54 55 56 57 58 59 5A 62 63 + 64 65 66 67 68 69 6A 72 73 74 75 76 77 78 79 7A + 82 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 + 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 + B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 + D5 D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA + Codes of length 15 bits (009 total): F2 F3 F4 F5 F6 F7 F8 F9 FA + Codes of length 16 bits (000 total): + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000023E3 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000023F1 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + +*** ERROR: Overread scan segment (after bitstring)! @ Offset: 0x00003EA5.1 +*** ERROR: Bad huffman code @ 0x00003EA5.6 +*** ERROR: Bad scan data in MCU(272,16): Lum CSS(0,0) @ Offset 0x00003EA5.1 + MCU located at pixel=(2176,128) +*** ERROR: Overread scan segment (before nCode)! @ Offset: 0x00003EA5.1 +*** ERROR: Bad huffman code @ 0x00003EA5.1 +*** ERROR: Bad scan data in MCU(272,16): Chr(Cb) CSS(0,0) @ Offset 0x00003EA5.1 + MCU located at pixel=(2176,128) +*** ERROR: Overread scan segment (before nCode)! @ Offset: 0x00003EA5.1 +*** ERROR: Bad huffman code @ 0x00003EA5.1 +*** ERROR: Bad scan data in MCU(272,16): Chr(Cr) CSS(0,0) @ Offset 0x00003EA5.1 + MCU located at pixel=(2176,128) +*** ERROR: Overread scan segment (before nCode)! @ Offset: 0x00003EA5.1 +*** ERROR: Bad huffman code @ 0x00003EA5.1 +*** ERROR: Bad scan data in MCU(0,17): Lum CSS(0,0) @ Offset 0x00003EA5.1 + MCU located at pixel=(0,136) +*** ERROR: Overread scan segment (before nCode)! @ Offset: 0x00003EA5.1 +*** ERROR: Bad huffman code @ 0x00003EA5.1 +*** ERROR: Bad scan data in MCU(0,17): Chr(Cb) CSS(0,0) @ Offset 0x00003EA5.1 + MCU located at pixel=(0,136) +*** ERROR: Overread scan segment (before nCode)! @ Offset: 0x00003EA5.1 +*** ERROR: Bad huffman code @ 0x00003EA5.1 +*** ERROR: Bad scan data in MCU(0,17): Chr(Cr) CSS(0,0) @ Offset 0x00003EA5.1 + MCU located at pixel=(0,136) +*** ERROR: Overread scan segment (before nCode)! @ Offset: 0x00003EA5.1 +*** ERROR: Bad huffman code @ 0x00003EA5.1 +*** ERROR: Bad scan data in MCU(0,18): Lum CSS(0,0) @ Offset 0x00003EA5.1 + MCU located at pixel=(0,144) + Only reported first 20 instances of this message... + + Compression stats: + Compression Ratio: 3031.33:1 + Bits per pixel: 0.01:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 4841 ( 99%) + # codes of length 03 bits: 33 ( 1%) + # codes of length 04 bits: 6 ( 0%) + # codes of length 05 bits: 1 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 9732 (100%) + # codes of length 02 bits: 23 ( 0%) + # codes of length 03 bits: 5 ( 0%) + # codes of length 04 bits: 0 ( 0%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 274 ( 5%) + # codes of length 03 bits: 297 ( 5%) + # codes of length 04 bits: 4903 ( 85%) + # codes of length 05 bits: 88 ( 2%) + # codes of length 06 bits: 26 ( 0%) + # codes of length 07 bits: 98 ( 2%) + # codes of length 08 bits: 25 ( 0%) + # codes of length 09 bits: 4 ( 0%) + # codes of length 10 bits: 14 ( 0%) + # codes of length 11 bits: 1 ( 0%) + # codes of length 12 bits: 2 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 17 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 9760 (100%) + # codes of length 02 bits: 5 ( 0%) + # codes of length 03 bits: 0 ( 0%) + # codes of length 04 bits: 14 ( 0%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 2 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[128] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1014, 0, 0] RGB=[254,254,254] @ MCU[ 0, 0] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 17 + Next position in scan buffer: Offset 0x00003EA5.1 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0012B1C9 + + +*** Searching Compression Signatures *** + + Signature: 01A20F69263117021CD16AEF44D6E650 + Signature (Rotated): 01A20F69263117021CD16AEF44D6E650 + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: OK [NIKON] [NIKON D300S] + EXIF Makernotes: NONE + EXIF Software: OK [Adobe Bridge CS6 (Windows)] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[Adobe Photoshop ] [Save As 08 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 2 - Image has high probability of being processed/edited + + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-A.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-A.jpg.txt new file mode 100644 index 0000000000..92adfb3159 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-A.jpg.txt @@ -0,0 +1,519 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue723-Ordered-Interleaved-Progressive-A.jpg] + Filesize: [42798] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 2 1 1 2 2 4 5 6 + DQT, Row #1: 1 1 1 2 3 6 6 6 + DQT, Row #2: 1 1 2 2 4 6 7 6 + DQT, Row #3: 1 2 2 3 5 9 8 6 + DQT, Row #4: 2 2 4 6 7 11 10 8 + DQT, Row #5: 2 4 6 6 8 10 11 9 + DQT, Row #6: 5 6 8 9 10 12 12 10 + DQT, Row #7: 7 9 10 10 11 10 10 10 + Approx quality factor = 95.04 (scaling=9.93 variance=1.25) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 2 2 2 5 10 10 10 10 + DQT, Row #1: 2 2 3 7 10 10 10 10 + DQT, Row #2: 2 3 6 10 10 10 10 10 + DQT, Row #3: 5 7 10 10 10 10 10 10 + DQT, Row #4: 10 10 10 10 10 10 10 10 + DQT, Row #5: 10 10 10 10 10 10 10 10 + DQT, Row #6: 10 10 10 10 10 10 10 10 + DQT, Row #7: 10 10 10 10 10 10 10 10 + Approx quality factor = 94.91 (scaling=10.18 variance=0.26) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 600 + Samples per Line = 600 + Image Size = 600 x 600 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 29 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 01 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (005 total): 04 05 06 07 08 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 010 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000D0 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000A58 + Huffman table length = 27 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 01 02 + Codes of length 04 bits (003 total): 03 04 05 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000A75 + Scan header length = 10 + Number of img components = 2 + Component[1]: selector=0x02, table=1(DC),0(AC) + Component[2]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000E55 + Huffman table length = 37 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (005 total): 02 04 05 11 12 + Codes of length 04 bits (004 total): 00 01 03 06 + Codes of length 05 bits (001 total): 30 + Codes of length 06 bits (005 total): 10 13 14 15 16 + Codes of length 07 bits (001 total): 40 + Codes of length 08 bits (001 total): 20 + Codes of length 09 bits (001 total): A0 + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 018 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000E7C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 2 + Successive approximation = 0x03 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000015BD + Huffman table length = 82 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 02 03 + Codes of length 04 bits (004 total): 00 04 05 11 + Codes of length 05 bits (002 total): 12 21 + Codes of length 06 bits (002 total): 13 31 + Codes of length 07 bits (011 total): 06 10 14 22 30 32 40 41 51 61 92 + Codes of length 08 bits (012 total): 15 23 25 52 53 54 71 73 91 A1 B1 C1 + Codes of length 09 bits (007 total): 20 24 33 42 72 81 93 + Codes of length 10 bits (006 total): 43 44 55 62 63 A2 + Codes of length 11 bits (003 total): 82 83 D1 + Codes of length 12 bits (006 total): 16 26 34 50 A0 B2 + Codes of length 13 bits (007 total): 35 45 64 84 A3 C2 E1 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 063 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001611 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 3 .. 63 + Successive approximation = 0x03 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002E3F + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 11 + Codes of length 03 bits (001 total): 00 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (004 total): 10 41 51 61 + Codes of length 06 bits (005 total): 20 71 81 91 F0 + Codes of length 07 bits (005 total): 30 A1 B1 C1 D1 + Codes of length 08 bits (001 total): F1 + Codes of length 09 bits (001 total): E1 + Codes of length 10 bits (001 total): 40 + Codes of length 11 bits (001 total): A0 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002E6B + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x32 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003F38 + Huffman table length = 43 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (002 total): 41 51 + Codes of length 06 bits (001 total): 61 + Codes of length 07 bits (004 total): 10 71 81 91 + Codes of length 08 bits (001 total): A1 + Codes of length 09 bits (005 total): 30 B1 C1 D1 F0 + Codes of length 10 bits (001 total): E1 + Codes of length 11 bits (001 total): F1 + Codes of length 12 bits (000 total): + Codes of length 13 bits (003 total): 20 40 A0 + Codes of length 14 bits (001 total): 50 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 024 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003F65 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00005B9B + Huffman table length = 58 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 00 02 03 + Codes of length 04 bits (003 total): 04 11 12 + Codes of length 05 bits (001 total): 21 + Codes of length 06 bits (005 total): 05 13 14 31 51 + Codes of length 07 bits (005 total): 10 15 20 30 41 + Codes of length 08 bits (005 total): 22 23 32 33 71 + Codes of length 09 bits (005 total): 24 34 61 81 F0 + Codes of length 10 bits (008 total): 80 91 A1 B1 C1 D1 E1 F1 + Codes of length 11 bits (003 total): 42 52 62 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 039 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00005BD7 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00006270 + Huffman table length = 57 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (004 total): 00 02 03 11 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (003 total): 12 21 31 + Codes of length 06 bits (002 total): 05 30 + Codes of length 07 bits (004 total): 10 13 14 20 + Codes of length 08 bits (003 total): 32 41 51 + Codes of length 09 bits (007 total): 15 22 23 61 71 81 F0 + Codes of length 10 bits (002 total): 91 A1 + Codes of length 11 bits (004 total): 24 25 33 80 + Codes of length 12 bits (007 total): 42 62 B1 C1 D1 E1 F1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 038 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000062AB + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00006827 + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 00 21 + Codes of length 05 bits (002 total): 31 41 + Codes of length 06 bits (002 total): 51 61 + Codes of length 07 bits (001 total): 71 + Codes of length 08 bits (004 total): 81 91 A1 B1 + Codes of length 09 bits (003 total): 30 C1 D1 + Codes of length 10 bits (001 total): F0 + Codes of length 11 bits (001 total): E1 + Codes of length 12 bits (001 total): 10 + Codes of length 13 bits (000 total): + Codes of length 14 bits (003 total): 40 A0 F1 + Codes of length 15 bits (001 total): 20 + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00006853 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000099AB + Huffman table length = 41 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (003 total): 31 41 61 + Codes of length 06 bits (003 total): 10 51 91 + Codes of length 07 bits (004 total): 20 71 81 B1 + Codes of length 08 bits (002 total): 30 A1 + Codes of length 09 bits (002 total): C1 F0 + Codes of length 10 bits (003 total): 80 E1 F1 + Codes of length 11 bits (001 total): D1 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000099D6 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000A0BC + Huffman table length = 41 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (001 total): 41 + Codes of length 06 bits (004 total): 10 51 61 71 + Codes of length 07 bits (002 total): 30 91 + Codes of length 08 bits (002 total): 20 81 + Codes of length 09 bits (002 total): A1 B1 + Codes of length 10 bits (002 total): C1 D1 + Codes of length 11 bits (003 total): 40 80 E1 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000A0E7 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000A72C + + +*** Searching Compression Signatures *** + + Signature: 01E764F3ECB6C14A51FF83F1FF6D546B + Signature (Rotated): 01E6610D026E8E6FE4BECEA9B3328A63 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[Minolta Co., Ltd. ] [DiMAGE F100 ] [ ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5400 ] [FINE ] No + CAM:[NIKON ] [E5700 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[NIKON ] [E8700 ] [FINE ] No + CAM:[OLYMPUS CORPORATION ] [C8080WZ ] [ ] No + CAM:[PENTAX ] [PENTAX K10D ] [ ] No + CAM:[SAMSUNG TECHWIN ] [Pro 815 ] [ ] No + CAM:[SAMSUNG TECHWIN ] [VLUU NV 7, NV 7 ] [ ] No + CAM:[SAMSUNG TECHWIN ] [VLUU NV10, NV10 ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-F828 ] [ ] No + CAM:[SONY ] [DSC-H1 ] [ ] No + CAM:[SONY ] [DSC-H2 ] [ ] No + CAM:[SONY ] [DSC-H5 ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-L1 ] [ ] No + CAM:[SONY ] [DSC-N1 ] [ ] No + CAM:[SONY ] [DSC-P150 ] [ ] No + CAM:[SONY ] [DSC-P200 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-V3 ] [ ] No + CAM:[SONY ] [DSC-W55 ] [ ] No + CAM:[SONY ] [DSC-W7 ] [ ] No + SW :[Apple ImageIO.framework ] [084 ] + SW :[IJG Library ] [095 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [095 ] + SW :[IrfanView ] [095 ] + SW :[idImager ] [095 ] + SW :[FastStone Image Viewer ] [095 ] + SW :[NeatImage ] [095 ] + SW :[Paint.NET ] [095 ] + SW :[Photomatix ] [095 ] + SW :[XnView ] [095 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-B.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-B.jpg.txt new file mode 100644 index 0000000000..bcbe9f7f1d --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-B.jpg.txt @@ -0,0 +1,477 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue723-Ordered-Interleaved-Progressive-B.jpg] + Filesize: [36937] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 5 8 10 12 + DQT, Row #1: 2 2 3 4 5 12 12 11 + DQT, Row #2: 3 3 3 5 8 11 14 11 + DQT, Row #3: 3 3 4 6 10 17 16 12 + DQT, Row #4: 4 4 7 11 14 22 21 15 + DQT, Row #5: 5 7 11 13 16 21 23 18 + DQT, Row #6: 10 13 16 17 21 24 24 20 + DQT, Row #7: 14 18 19 20 22 20 21 20 + Approx quality factor = 90.06 (scaling=19.88 variance=1.14) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 3 4 5 9 20 20 20 20 + DQT, Row #1: 4 4 5 13 20 20 20 20 + DQT, Row #2: 5 5 11 20 20 20 20 20 + DQT, Row #3: 9 13 20 20 20 20 20 20 + DQT, Row #4: 20 20 20 20 20 20 20 20 + DQT, Row #5: 20 20 20 20 20 20 20 20 + DQT, Row #6: 20 20 20 20 20 20 20 20 + DQT, Row #7: 20 20 20 20 20 20 20 20 + Approx quality factor = 89.93 (scaling=20.14 variance=0.34) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 600 + Samples per Line = 600 + Image Size = 600 x 600 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 30 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (000 total): + Codes of length 04 bits (007 total): 02 03 04 05 06 07 08 + Codes of length 05 bits (001 total): 01 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (001 total): 0A + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 011 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000D1 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000A95 + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 04 05 + Codes of length 04 bits (003 total): 01 03 06 + Codes of length 05 bits (001 total): 02 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (001 total): 08 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000AB3 + Scan header length = 10 + Number of img components = 2 + Component[1]: selector=0x02, table=1(DC),0(AC) + Component[2]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000E60 + Huffman table length = 54 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (006 total): 00 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (003 total): 11 12 13 + Codes of length 06 bits (002 total): 21 50 + Codes of length 07 bits (004 total): 07 10 14 15 + Codes of length 08 bits (004 total): 20 22 23 31 + Codes of length 09 bits (005 total): 16 24 30 32 36 + Codes of length 10 bits (003 total): 25 40 41 + Codes of length 11 bits (004 total): 17 42 43 80 + Codes of length 12 bits (003 total): 26 33 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 035 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000E98 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00001E73 + Huffman table length = 75 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (002 total): 00 11 + Codes of length 05 bits (002 total): 04 12 + Codes of length 06 bits (005 total): 13 21 31 41 51 + Codes of length 07 bits (006 total): 10 22 52 61 71 81 + Codes of length 08 bits (010 total): 05 14 20 32 42 50 91 A1 B1 C1 + Codes of length 09 bits (005 total): 23 33 62 72 D1 + Codes of length 10 bits (010 total): 24 30 40 53 63 73 82 92 E1 F0 + Codes of length 11 bits (005 total): 15 34 35 43 A2 + Codes of length 12 bits (004 total): 64 74 80 B2 + Codes of length 13 bits (003 total): 60 93 F1 + Codes of length 14 bits (001 total): A3 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 056 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001EC0 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003A1E + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (002 total): 31 41 + Codes of length 06 bits (005 total): 10 51 61 71 81 + Codes of length 07 bits (004 total): 50 91 A1 B1 + Codes of length 08 bits (002 total): C1 F0 + Codes of length 09 bits (003 total): 20 D1 E1 + Codes of length 10 bits (001 total): F1 + Codes of length 11 bits (001 total): 40 + Codes of length 12 bits (001 total): 80 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003A4A + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00005386 + Huffman table length = 43 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 00 21 + Codes of length 05 bits (002 total): 31 41 + Codes of length 06 bits (001 total): 51 + Codes of length 07 bits (003 total): 61 71 81 + Codes of length 08 bits (004 total): 50 91 A1 B1 + Codes of length 09 bits (002 total): 10 C1 + Codes of length 10 bits (003 total): D1 E1 F0 + Codes of length 11 bits (000 total): + Codes of length 12 bits (003 total): 20 80 F1 + Codes of length 13 bits (001 total): 30 + Codes of length 14 bits (001 total): 40 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 024 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000053B3 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00007B5B + Huffman table length = 50 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (003 total): 13 31 40 + Codes of length 07 bits (003 total): 06 22 41 + Codes of length 08 bits (002 total): 14 32 + Codes of length 09 bits (004 total): 10 16 23 33 + Codes of length 10 bits (005 total): 15 20 42 60 61 + Codes of length 11 bits (005 total): 24 34 50 51 52 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 031 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00007B8F + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 12 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000081EE + Huffman table length = 49 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (004 total): 21 31 41 51 + Codes of length 05 bits (003 total): 02 61 71 + Codes of length 06 bits (007 total): 10 40 81 91 A1 B1 C1 + Codes of length 07 bits (003 total): D1 E1 F0 + Codes of length 08 bits (003 total): 03 50 F1 + Codes of length 09 bits (004 total): 12 22 30 60 + Codes of length 10 bits (003 total): 20 32 70 + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 030 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00008221 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 13 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000084F2 + Huffman table length = 48 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (002 total): 03 04 + Codes of length 04 bits (001 total): 05 + Codes of length 05 bits (003 total): 00 11 12 + Codes of length 06 bits (003 total): 06 21 31 + Codes of length 07 bits (003 total): 13 22 40 + Codes of length 08 bits (002 total): 14 41 + Codes of length 09 bits (005 total): 07 10 15 32 50 + Codes of length 10 bits (003 total): 42 60 61 + Codes of length 11 bits (005 total): 20 23 33 43 51 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 029 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00008524 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 12 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00008C10 + Huffman table length = 51 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (002 total): 00 21 + Codes of length 05 bits (004 total): 02 31 41 51 + Codes of length 06 bits (002 total): 61 71 + Codes of length 07 bits (009 total): 03 12 40 81 91 A1 B1 C1 D1 + Codes of length 08 bits (003 total): 10 E1 F0 + Codes of length 09 bits (003 total): 22 32 F1 + Codes of length 10 bits (004 total): 04 50 52 70 + Codes of length 11 bits (003 total): 20 42 60 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 032 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00008C45 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 13 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00009047 + + +*** Searching Compression Signatures *** + + Signature: 013BA18D5561625796E986FDBC09F846 + Signature (Rotated): 01AC57E12793DFA7C46C704625C5AF0F + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[??? ] [Treo 680 ] [ ] Yes + CAM:[Canon ] [Canon PowerShot Pro1 ] [fine ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E3100 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5000 ] [FINE ] No + CAM:[NIKON ] [E5700 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[NIKON ] [E885 ] [FINE ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 9530 ] [Superfine ] Yes + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-W1 ] [ ] No + CAM:[SONY ] [SONY ] [ ] No + SW :[ACDSee ] [ ] + SW :[FixFoto ] [fine ] + SW :[IJG Library ] [090 ] + SW :[ZoomBrowser EX ] [high ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [090 ] + SW :[IrfanView ] [090 ] + SW :[idImager ] [090 ] + SW :[FastStone Image Viewer ] [090 ] + SW :[NeatImage ] [090 ] + SW :[Paint.NET ] [090 ] + SW :[Photomatix ] [090 ] + SW :[XnView ] [090 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-C.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-C.jpg.txt new file mode 100644 index 0000000000..c76b744313 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-C.jpg.txt @@ -0,0 +1,484 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue723-Ordered-Interleaved-Progressive-C.jpg] + Filesize: [46799] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 38 x 38 DPcm (dots per cm) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 2 1 1 2 2 4 5 6 + DQT, Row #1: 1 1 1 2 3 6 6 6 + DQT, Row #2: 1 1 2 2 4 6 7 6 + DQT, Row #3: 1 2 2 3 5 9 8 6 + DQT, Row #4: 2 2 4 6 7 11 10 8 + DQT, Row #5: 2 4 6 6 8 10 11 9 + DQT, Row #6: 5 6 8 9 10 12 12 10 + DQT, Row #7: 7 9 10 10 11 10 10 10 + Approx quality factor = 95.04 (scaling=9.93 variance=1.25) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 2 2 2 5 10 10 10 10 + DQT, Row #1: 2 2 3 7 10 10 10 10 + DQT, Row #2: 2 3 6 10 10 10 10 10 + DQT, Row #3: 5 7 10 10 10 10 10 10 + DQT, Row #4: 10 10 10 10 10 10 10 10 + DQT, Row #5: 10 10 10 10 10 10 10 10 + DQT, Row #6: 10 10 10 10 10 10 10 10 + DQT, Row #7: 10 10 10 10 10 10 10 10 + Approx quality factor = 94.91 (scaling=10.18 variance=0.26) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 517 + Samples per Line = 502 + Image Size = 502 x 517 + Raw Image Orientation = Portrait + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 30 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (001 total): 06 + Codes of length 04 bits (004 total): 04 05 07 08 + Codes of length 05 bits (003 total): 02 03 09 + Codes of length 06 bits (001 total): 01 + Codes of length 07 bits (001 total): 0A + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 011 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000D1 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000858 + Huffman table length = 29 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (001 total): 05 + Codes of length 04 bits (005 total): 02 03 04 06 07 + Codes of length 05 bits (001 total): 01 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 010 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000877 + Scan header length = 10 + Number of img components = 2 + Component[1]: selector=0x02, table=1(DC),0(AC) + Component[2]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000012C2 + Huffman table length = 67 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 03 + Codes of length 03 bits (004 total): 01 02 04 05 + Codes of length 04 bits (002 total): 00 06 + Codes of length 05 bits (001 total): 11 + Codes of length 06 bits (002 total): 07 12 + Codes of length 07 bits (004 total): 13 14 21 50 + Codes of length 08 bits (004 total): 08 15 22 31 + Codes of length 09 bits (002 total): 17 23 + Codes of length 10 bits (006 total): 10 16 20 24 32 41 + Codes of length 11 bits (008 total): 25 33 34 42 51 52 54 62 + Codes of length 12 bits (004 total): 26 30 35 40 + Codes of length 13 bits (005 total): 18 27 37 55 56 + Codes of length 14 bits (005 total): 44 53 61 70 80 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 048 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001307 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 12 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002FBE + Huffman table length = 80 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 02 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 12 21 31 + Codes of length 06 bits (005 total): 13 22 41 51 61 + Codes of length 07 bits (011 total): 05 10 14 32 50 71 81 91 A1 B1 C1 + Codes of length 08 bits (007 total): 20 23 42 52 62 82 D1 + Codes of length 09 bits (009 total): 15 30 33 53 72 92 A2 B2 E1 + Codes of length 10 bits (006 total): 24 40 43 73 C2 E2 + Codes of length 11 bits (004 total): 06 63 D2 F0 + Codes of length 12 bits (005 total): 25 54 75 A3 B3 + Codes of length 13 bits (005 total): 44 64 70 80 83 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 061 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003010 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 13 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000048A9 + Huffman table length = 43 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (001 total): 41 + Codes of length 06 bits (003 total): 51 61 71 + Codes of length 07 bits (003 total): 10 81 A1 + Codes of length 08 bits (004 total): 50 91 B1 C1 + Codes of length 09 bits (003 total): 20 D1 F0 + Codes of length 10 bits (001 total): F1 + Codes of length 11 bits (001 total): E1 + Codes of length 12 bits (001 total): 30 + Codes of length 13 bits (001 total): 70 + Codes of length 14 bits (001 total): 80 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 024 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000048D6 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000060D3 + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 00 21 + Codes of length 05 bits (002 total): 31 41 + Codes of length 06 bits (002 total): 51 61 + Codes of length 07 bits (001 total): 71 + Codes of length 08 bits (004 total): 50 81 91 A1 + Codes of length 09 bits (002 total): 10 B1 + Codes of length 10 bits (002 total): C1 F0 + Codes of length 11 bits (002 total): D1 F1 + Codes of length 12 bits (003 total): 30 70 E1 + Codes of length 13 bits (001 total): 20 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000060FF + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00007FD1 + Huffman table length = 54 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 03 + Codes of length 03 bits (004 total): 01 02 04 05 + Codes of length 04 bits (001 total): 00 + Codes of length 05 bits (002 total): 06 11 + Codes of length 06 bits (006 total): 07 12 13 21 31 50 + Codes of length 07 bits (001 total): 14 + Codes of length 08 bits (002 total): 15 22 + Codes of length 09 bits (005 total): 10 23 32 33 41 + Codes of length 10 bits (003 total): 16 17 20 + Codes of length 11 bits (002 total): 24 34 + Codes of length 12 bits (007 total): 25 26 30 40 42 51 70 + Codes of length 13 bits (001 total): 80 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 035 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00008009 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 8 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00008F76 + Huffman table length = 59 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 00 02 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (004 total): 03 12 41 51 + Codes of length 06 bits (003 total): 61 71 81 + Codes of length 07 bits (005 total): 10 22 50 91 A1 + Codes of length 08 bits (007 total): 32 52 B1 C1 D1 F0 F1 + Codes of length 09 bits (002 total): 04 13 + Codes of length 10 bits (004 total): 20 23 42 72 + Codes of length 11 bits (006 total): 62 70 80 82 92 E1 + Codes of length 12 bits (003 total): 30 60 A2 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 040 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00008FB3 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 9 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00009B28 + Huffman table length = 51 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 03 + Codes of length 03 bits (004 total): 01 02 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (003 total): 00 07 11 + Codes of length 06 bits (003 total): 12 13 31 + Codes of length 07 bits (003 total): 08 21 50 + Codes of length 08 bits (003 total): 10 14 15 + Codes of length 09 bits (004 total): 20 23 32 41 + Codes of length 10 bits (001 total): 16 + Codes of length 11 bits (003 total): 22 24 40 + Codes of length 12 bits (005 total): 17 18 33 34 70 + Codes of length 13 bits (001 total): 80 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 032 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00009B5D + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 8 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000AB99 + Huffman table length = 62 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 00 02 11 + Codes of length 04 bits (002 total): 03 21 + Codes of length 05 bits (004 total): 12 31 41 51 + Codes of length 06 bits (003 total): 04 61 71 + Codes of length 07 bits (005 total): 10 22 32 50 81 + Codes of length 08 bits (004 total): 13 91 A1 B1 + Codes of length 09 bits (008 total): 20 23 42 52 62 72 C1 D1 + Codes of length 10 bits (005 total): 05 14 92 E1 F0 + Codes of length 11 bits (003 total): 30 33 F1 + Codes of length 12 bits (005 total): 70 80 82 90 A2 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 043 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000ABD9 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 9 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000B6CD + + +*** Searching Compression Signatures *** + + Signature: 01E764F3ECB6C14A51FF83F1FF6D546B + Signature (Rotated): 01E6610D026E8E6FE4BECEA9B3328A63 + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[Minolta Co., Ltd. ] [DiMAGE F100 ] [ ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5400 ] [FINE ] No + CAM:[NIKON ] [E5700 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[NIKON ] [E8700 ] [FINE ] No + CAM:[OLYMPUS CORPORATION ] [C8080WZ ] [ ] No + CAM:[PENTAX ] [PENTAX K10D ] [ ] No + CAM:[SAMSUNG TECHWIN ] [Pro 815 ] [ ] No + CAM:[SAMSUNG TECHWIN ] [VLUU NV 7, NV 7 ] [ ] No + CAM:[SAMSUNG TECHWIN ] [VLUU NV10, NV10 ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-F828 ] [ ] No + CAM:[SONY ] [DSC-H1 ] [ ] No + CAM:[SONY ] [DSC-H2 ] [ ] No + CAM:[SONY ] [DSC-H5 ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-L1 ] [ ] No + CAM:[SONY ] [DSC-N1 ] [ ] No + CAM:[SONY ] [DSC-P150 ] [ ] No + CAM:[SONY ] [DSC-P200 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-V3 ] [ ] No + CAM:[SONY ] [DSC-W55 ] [ ] No + CAM:[SONY ] [DSC-W7 ] [ ] No + SW :[Apple ImageIO.framework ] [084 ] + SW :[IJG Library ] [095 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [095 ] + SW :[IrfanView ] [095 ] + SW :[idImager ] [095 ] + SW :[FastStone Image Viewer ] [095 ] + SW :[NeatImage ] [095 ] + SW :[Paint.NET ] [095 ] + SW :[Photomatix ] [095 ] + SW :[XnView ] [095 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/issue750-exif-load.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/issue750-exif-load.jpg.txt new file mode 100644 index 0000000000..6070e1cdab --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/issue750-exif-load.jpg.txt @@ -0,0 +1,772 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\issue750-exif-load.jpg] + Filesize: [36885] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000002 + Length = 3656 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000014 + Dir Length = 0x0010 + [Make ] = "Canon" + [Model ] = "Canon EOS 70D" + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 720000/10000 + [YResolution ] = 720000/10000 + [ResolutionUnit ] = Inch + [Software ] = "Adobe Photoshop CS6 (Windows)" + [DateTime ] = "2018:02:28 17:51:59" + [YCbCrPositioning ] = Centered + [ExifOffset ] = @ 0x012C + [GPSOffset ] = @ 0x04C8 + Offset to Next IFD = 0x000004DC + + EXIF IFD1 @ Absolute 0x000004E8 + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x053A = @ 0x0546 + [JpegIFByteCount ] = 0x[00000906] / 2310 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x00000138 + Dir Length = 0x0025 + [ExposureTime ] = 1/60 s + [FNumber ] = F11.0 + [ExposureProgram ] = Manual + [ISOSpeedRatings ] = 100 + [ExifVersion ] = 02.30 + [DateTimeOriginal ] = "2017:09:14 14:41:54" + [DateTimeDigitized ] = "2017:09:14 14:41:54" + [ComponentsConfiguration ] = [Y Cb Cr .] + [ShutterSpeedValue ] = 393216/65536 + [ApertureValue ] = 458752/65536 + [ExposureBiasValue ] = 0.00 eV + [MeteringMode ] = Pattern + [Flash ] = Flash did not fire + [FocalLength ] = 50 mm + [UserComment ] = "" + [SubSecTime ] = "277" + [SubSecTimeOriginal ] = "00" + [SubSecTimeDigitized ] = "00" + [FlashPixVersion ] = 01.00 + [ColorSpace ] = sRGB + [ExifImageWidth ] = 0x[000001D3] / 467 + [ExifImageHeight ] = 0x[000002BC] / 700 + [ExifInteroperabilityOffset ] = @ 0x04A8 + [FocalPlaneXResolution ] = 5472000/899 + [FocalPlaneYResolution ] = 3648000/599 + [FocalPlaneResolutionUnit ] = Inch + [CustomRendered ] = Normal process + [ExposureMode ] = Manual exposure + [WhiteBalance ] = Auto white balance + [SceneCaptureType ] = Standard + + EXIF GPSIFD @ Absolute 0x000004D4 + Dir Length = 0x0001 + [GPSVersionID ] = 2.3.0.0 + + EXIF InteropIFD @ Absolute 0x000004B4 + Dir Length = 0x0002 + [InteroperabilityIndex ] = "R98" + [InteroperabilityVersion ] = 01.00 + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x00000E4C + Length = 4648 + Identifier = [Photoshop 3.0] + 8BIM: [0x0404] Name="" Len=[0x002C] DefinedName="IPTC-NAA record" + IPTC [001:090] Coded Character Set = "%G" + IPTC [002:000] Record Version = 51658 + IPTC [002:055] Date Created = "20170914" + IPTC [002:060] Time Created = "144154+0000" + 8BIM: [0x0425] Name="" Len=[0x0010] DefinedName="Caption digest" + Caption digest = | 0x8B 58 80 D1 16 85 C7 6D 47 04 59 0B 61 59 FA 69 | .X.....mG.Y.aY.i + 8BIM: [0x043A] Name="" Len=[0x00E5] DefinedName="Print Information" + Print Information = + | 0x00 00 00 10 00 00 00 01 00 00 00 00 00 0B 70 72 | ..............pr + | 0x69 6E 74 4F 75 74 70 75 74 00 00 00 05 00 00 00 | intOutput....... + | 0x00 50 73 74 53 62 6F 6F 6C 01 00 00 00 00 49 6E | .PstSbool.....In + | 0x74 65 65 6E 75 6D 00 00 00 00 49 6E 74 65 00 00 | teenum....Inte.. + | 0x00 00 43 6C 72 6D 00 00 00 0F 70 72 69 6E 74 53 | ..Clrm....printS + | 0x69 78 74 65 65 6E 42 69 74 62 6F 6F 6C 00 00 00 | ixteenBitbool... + | 0x00 0B 70 72 69 6E 74 65 72 4E 61 6D 65 54 45 58 | ..printerNameTEX + | 0x54 00 00 00 01 00 00 00 00 00 0F 70 72 69 6E 74 | T..........print + | ... + 8BIM: [0x043B] Name="" Len=[0x022D] DefinedName="Print Style" + Print Style = + | 0x00 00 00 10 00 00 00 01 00 00 00 00 00 12 70 72 | ..............pr + | 0x69 6E 74 4F 75 74 70 75 74 4F 70 74 69 6F 6E 73 | intOutputOptions + | 0x00 00 00 17 00 00 00 00 43 70 74 6E 62 6F 6F 6C | ........Cptnbool + | 0x00 00 00 00 00 43 6C 62 72 62 6F 6F 6C 00 00 00 | .....Clbrbool... + | 0x00 00 52 67 73 4D 62 6F 6F 6C 00 00 00 00 00 43 | ..RgsMbool.....C + | 0x72 6E 43 62 6F 6F 6C 00 00 00 00 00 43 6E 74 43 | rnCbool.....CntC + | 0x62 6F 6F 6C 00 00 00 00 00 4C 62 6C 73 62 6F 6F | bool.....Lblsboo + | 0x6C 00 00 00 00 00 4E 67 74 76 62 6F 6F 6C 00 00 | l.....Ngtvbool.. + | ... + 8BIM: [0x03ED] Name="" Len=[0x0010] DefinedName="ResolutionInfo structure" + Horizontal resolution = 72 pixels per inch + Width unit = cm + Vertical resolution = 72 pixels per inch + Height unit = cm + 8BIM: [0x0426] Name="" Len=[0x000E] DefinedName="Print scale" + Style = centered + X location = 0.00000 + Y location = 0.00000 + Scale = 1.00000 + 8BIM: [0x040D] Name="" Len=[0x0004] DefinedName="Global Angle" + Global Angle = 30 degrees + 8BIM: [0x0419] Name="" Len=[0x0004] DefinedName="Global Altitude" + Global Altitude = 30 + 8BIM: [0x03F3] Name="" Len=[0x0009] DefinedName="Print flags" + Labels = false + Crop marks = false + Color bars = false + Registration marks = false + Negative = false + Flip = false + Interpolate = false + Caption = false + Print flags = true + 8BIM: [0x2710] Name="" Len=[0x000A] DefinedName="Print flags information" + Version = 1 + Center crop marks = 0 + Reserved = 0 + Bleed width value = 0 + Bleed width scale = 2 + 8BIM: [0x03F5] Name="" Len=[0x0048] DefinedName="Color halftoning information" + Color halftoning information = + | 0x00 2F 66 66 00 01 00 6C 66 66 00 06 00 00 00 00 | ./ff...lff...... + | 0x00 01 00 2F 66 66 00 01 00 A1 99 9A 00 06 00 00 | .../ff.......... + | 0x00 00 00 01 00 32 00 00 00 01 00 5A 00 00 00 06 | .....2.....Z.... + | 0x00 00 00 00 00 01 00 35 00 00 00 01 00 2D 00 00 | .......5.....-.. + | 0x00 06 00 00 00 00 00 01 | ........ + 8BIM: [0x03F8] Name="" Len=[0x0070] DefinedName="Color transfer functions" + Color transfer functions = + | 0x00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF | ................ + | 0xFF FF FF FF FF FF FF FF 03 E8 00 00 00 00 FF FF | ................ + | 0xFF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF | ................ + | 0xFF FF FF FF 03 E8 00 00 00 00 FF FF FF FF FF FF | ................ + | 0xFF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF | ................ + | 0x03 E8 00 00 00 00 FF FF FF FF FF FF FF FF FF FF | ................ + | 0xFF FF FF FF FF FF FF FF FF FF FF FF 03 E8 00 00 | ................ + 8BIM: [0x0408] Name="" Len=[0x0010] DefinedName="Grid and guides information" + Version = 1 + Grid Horizontal = 576 + Grid Vertical = 576 + Number of Guide Resources = 0 + 8BIM: [0x041E] Name="" Len=[0x0004] DefinedName="URL List" + URL List = | 0x00 00 00 00 | .... + 8BIM: [0x041A] Name="" Len=[0x0341] DefinedName="Slices" + Slice Header: + Version = 6 + Bound Rect (top) = 0 + Bound Rect (left) = 0 + Bound Rect (bottom) = 700 + Bound Rect (right) = 467 + Name of group of slices = "513566" + Number of slices = 1 + ----- + Slice #0: + Slice Resource: + ID = 0 + Group ID = 0 + Origin = 0 + Name = "" + Type = 1 + Position (top) = 0 + Position (left) = 0 + Position (bottom) = 467 + Position (right) = 700 + URL = "" + Target = "" + Message = "" + Alt Tag = "" + Cell text is HTML = true + Cell text = "" + Horizontal alignment = 0 + Vertical alignment = 0 + Alpha color = 0 + Red = 0 + Green = 0 + Blue = 0 + Descriptor version = 16 + Descriptor: + Name from classID = "" + classID = "null" + Num items in descriptor = 2 + ----- + Descriptor item #0: + Key = "bounds" + OSType key = "Objc" + Descriptor: + Name from classID = "" + classID = "Rct1" + Num items in descriptor = 4 + ----- + Descriptor item #0: + Key = "Top " + OSType key = "long" + Value = 0 + Descriptor item #1: + Key = "Left" + OSType key = "long" + Value = 0 + Descriptor item #2: + Key = "Btom" + OSType key = "long" + Value = 700 + Descriptor item #3: + Key = "Rght" + OSType key = "long" + Value = 467 + ----- + Descriptor item #1: + Key = "slices" + OSType key = "VlLs" + Num items in list = 1 + ----- + Item #0: + OSType key = "" + Descriptor: + Name from classID = "" + classID = "slice" + Num items in descriptor = 18 + ----- + Descriptor item #0: + Key = "sliceID" + OSType key = "long" + Value = 0 + Descriptor item #1: + Key = "groupID" + OSType key = "long" + Value = 0 + Descriptor item #2: + Key = "origin" + OSType key = "enum" + Type = "ESliceOrigin" + Enum = "autoGenerated" + Descriptor item #3: + Key = "Type" + OSType key = "enum" + Type = "ESliceType" + Enum = "Img " + Descriptor item #4: + Key = "bounds" + OSType key = "Objc" + Descriptor: + Name from classID = "" + classID = "Rct1" + Num items in descriptor = 4 + ----- + Descriptor item #0: + Key = "Top " + OSType key = "long" + Value = 0 + Descriptor item #1: + Key = "Left" + OSType key = "long" + Value = 0 + Descriptor item #2: + Key = "Btom" + OSType key = "long" + Value = 700 + Descriptor item #3: + Key = "Rght" + OSType key = "long" + Value = 467 + ----- + Descriptor item #5: + Key = "url" + OSType key = "TEXT" + String = "" + Descriptor item #6: + Key = "null" + OSType key = "TEXT" + String = "" + Descriptor item #7: + Key = "Msge" + OSType key = "TEXT" + String = "" + Descriptor item #8: + Key = "altTag" + OSType key = "TEXT" + String = "" + Descriptor item #9: + Key = "cellTextIsHTML" + OSType key = "bool" + Value = true + Descriptor item #10: + Key = "cellText" + OSType key = "TEXT" + String = "" + Descriptor item #11: + Key = "horzAlign" + OSType key = "enum" + Type = "ESliceHorzAlign" + Enum = "default" + Descriptor item #12: + Key = "vertAlign" + OSType key = "enum" + Type = "ESliceVertAlign" + Enum = "default" + Descriptor item #13: + Key = "bgColorType" + OSType key = "enum" + Type = "ESliceBGColorType" + Enum = "None" + Descriptor item #14: + Key = "topOutset" + OSType key = "long" + Value = 0 + Descriptor item #15: + Key = "leftOutset" + OSType key = "long" + Value = 0 + Descriptor item #16: + Key = "bottomOutset" + OSType key = "long" + Value = 0 + Descriptor item #17: + Key = "rightOutset" + OSType key = "long" + Value = 0 + ----- + ----- + ----- + ----- + 8BIM: [0x0428] Name="" Len=[0x000C] DefinedName="Pixel Aspect Ratio" + Version = 2 + X/Y Ratio = 1.00000 + 8BIM: [0x0414] Name="" Len=[0x0004] DefinedName="Document-specific IDs seed number" + Base value = 1 + 8BIM: [0x040C] Name="" Len=[0x0922] DefinedName="Thumbnail resources" + Format = 1 + Width of thumbnail = 107 pixels + Height of thumbnail = 160 pixels + Widthbytes = 324 bytes + Total size = 51840 bytes + Size after compression = 2310 bytes + Bits per pixel = 24 bits + Number of planes = 1 + JFIF data @ 0x000016FA + 8BIM: [0x0421] Name="" Len=[0x0055] DefinedName="Version Info" + Version = 1 + hasRealMergedData = 1 + Writer name = "Adobe Photoshop" + Reader name = "Adobe Photoshop CS6" + File version = 1 + 8BIM: [0x0406] Name="" Len=[0x0007] DefinedName="JPEG quality" + Photoshop Save As Quality = 7 + Photoshop Save Format = "Standard" + Photoshop Save Progressive Scans = "3 Scans" + ??? = 1 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00002076 + Length = 3752 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00002F20 + Length = 3160 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 3144 bytes + Preferred CMM Type : 'Lino' (0x4C696E6F) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 1998-02-09 06:49:00 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Microsoft Corporation ('MSFT' (0x4D534654)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : 'IEC ' (0x49454320) + Device Model : 'sRGB' (0x73524742) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'HP ' (0x48502020) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x00003B7A + Length = 14 + DCTEncodeVersion = 100 + APP14Flags0 = 0 + APP14Flags1 = 0 + ColorTransform = 1 [YCbCr] + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00003B8A + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 10 7 7 10 15 18 20 17 + DQT, Row #1: 7 8 8 10 13 16 12 12 + DQT, Row #2: 7 8 8 10 16 12 12 12 + DQT, Row #3: 10 10 10 18 12 12 12 12 + DQT, Row #4: 15 13 16 12 12 12 12 12 + DQT, Row #5: 18 16 12 12 12 12 12 12 + DQT, Row #6: 20 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 83.48 (scaling=33.04 variance=462.13) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 11 12 21 34 20 20 17 17 + DQT, Row #1: 12 19 24 14 14 12 12 12 + DQT, Row #2: 21 24 14 14 12 12 12 12 + DQT, Row #3: 34 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 87.98 (scaling=24.05 variance=592.80) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00003C10 + Frame header length = 17 + Precision = 8 + Number of Lines = 700 + Samples per Line = 467 + Image Size = 467 x 700 + Raw Image Orientation = Portrait + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x00003C23 + Length = 4 + interval = 59 + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003C29 + Huffman table length = 418 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (007 total): 04 05 03 02 06 01 00 + Codes of length 04 bits (001 total): 07 + Codes of length 05 bits (001 total): 08 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (001 total): 0A + Codes of length 08 bits (001 total): 0B + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 00 + Codes of length 03 bits (002 total): 02 03 + Codes of length 04 bits (003 total): 04 05 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 11 04 00 + Codes of length 05 bits (003 total): 05 21 12 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 51 06 13 61 + Codes of length 08 bits (002 total): 22 71 + Codes of length 09 bits (006 total): 81 14 32 91 A1 07 + Codes of length 10 bits (007 total): 15 B1 42 23 C1 52 D1 + Codes of length 11 bits (003 total): E1 33 16 + Codes of length 12 bits (004 total): 62 F0 24 72 + Codes of length 13 bits (002 total): 82 F1 + Codes of length 14 bits (006 total): 25 43 34 53 92 A2 + Codes of length 15 bits (002 total): B2 63 + Codes of length 16 bits (115 total): 73 C2 35 44 27 93 A3 B3 36 17 54 64 74 C3 D2 E2 + 08 26 83 09 0A 18 19 84 94 45 46 A4 B4 56 D3 55 + 28 1A F2 E3 F3 C4 D4 E4 F4 65 75 85 95 A5 B5 C5 + D5 E5 F5 66 76 86 96 A6 B6 C6 D6 E6 F6 37 47 57 + 67 77 87 97 A7 B7 C7 D7 E7 F7 38 48 58 68 78 88 + 98 A8 B8 C8 D8 E8 F8 29 39 49 59 69 79 89 99 A9 + B9 C9 D9 E9 F9 2A 3A 4A 5A 6A 7A 8A 9A AA BA CA + DA EA FA + Total number of codes: 162 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 00 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (002 total): 04 21 + Codes of length 06 bits (003 total): 12 31 41 + Codes of length 07 bits (005 total): 05 51 13 61 22 + Codes of length 08 bits (005 total): 06 71 81 91 32 + Codes of length 09 bits (004 total): A1 B1 F0 14 + Codes of length 10 bits (005 total): C1 D1 E1 23 42 + Codes of length 11 bits (006 total): 15 52 62 72 F1 33 + Codes of length 12 bits (004 total): 24 34 43 82 + Codes of length 13 bits (008 total): 16 92 53 25 A2 63 B2 C2 + Codes of length 14 bits (003 total): 07 73 D2 + Codes of length 15 bits (003 total): 35 E2 44 + Codes of length 16 bits (109 total): 83 17 54 93 08 09 0A 18 19 26 36 45 1A 27 64 74 + 55 37 F2 A3 B3 C3 28 29 D3 E3 F3 84 94 A4 B4 C4 + D4 E4 F4 65 75 85 95 A5 B5 C5 D5 E5 F5 46 56 66 + 76 86 96 A6 B6 C6 D6 E6 F6 47 57 67 77 87 97 A7 + B7 C7 D7 E7 F7 38 48 58 68 78 88 98 A8 B8 C8 D8 + E8 F8 39 49 59 69 79 89 99 A9 B9 C9 D9 E9 F9 2A + 3A 4A 5A 6A 7A 8A 9A AA BA CA DA EA FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003DCD + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00003DDB + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00009013.0 + + Compression stats: + Compression Ratio: 46.60:1 + Bits per pixel: 0.52:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 4910 ( 95%) + # codes of length 04 bits: 280 ( 5%) + # codes of length 05 bits: 2 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 9997 ( 96%) + # codes of length 03 bits: 335 ( 3%) + # codes of length 04 bits: 52 ( 1%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 5649 ( 33%) + # codes of length 03 bits: 1560 ( 9%) + # codes of length 04 bits: 6758 ( 39%) + # codes of length 05 bits: 1189 ( 7%) + # codes of length 06 bits: 349 ( 2%) + # codes of length 07 bits: 488 ( 3%) + # codes of length 08 bits: 255 ( 1%) + # codes of length 09 bits: 351 ( 2%) + # codes of length 10 bits: 254 ( 1%) + # codes of length 11 bits: 70 ( 0%) + # codes of length 12 bits: 76 ( 0%) + # codes of length 13 bits: 14 ( 0%) + # codes of length 14 bits: 115 ( 1%) + # codes of length 15 bits: 41 ( 0%) + # codes of length 16 bits: 88 ( 1%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 10917 ( 93%) + # codes of length 03 bits: 435 ( 4%) + # codes of length 04 bits: 77 ( 1%) + # codes of length 05 bits: 75 ( 1%) + # codes of length 06 bits: 121 ( 1%) + # codes of length 07 bits: 47 ( 0%) + # codes of length 08 bits: 36 ( 0%) + # codes of length 09 bits: 5 ( 0%) + # codes of length 10 bits: 15 ( 0%) + # codes of length 11 bits: 39 ( 0%) + # codes of length 12 bits: 11 ( 0%) + # codes of length 13 bits: 3 ( 0%) + # codes of length 14 bits: 2 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 1 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[222] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1020, 0, 0] RGB=[255,255,255] @ MCU[ 0, 0] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 87 + Next position in scan buffer: Offset 0x00009012.5 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00009013 + + +*** Embedded JPEG Thumbnail *** + Offset: 0x00000546 + Length: 0x00000906 (2310) + + * Embedded Thumb Marker: SOI + + * Embedded Thumb Marker: APP13 + Length = 12 + + * Embedded Thumb Marker: APP14 + Length = 14 + + * Embedded Thumb Marker: DQT + Length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance, typically) + DQT, Row #0: 12 8 8 12 17 21 24 17 + DQT, Row #1: 8 9 9 11 15 19 12 12 + DQT, Row #2: 8 9 10 12 19 12 12 12 + DQT, Row #3: 12 11 12 21 12 12 12 12 + DQT, Row #4: 17 15 19 12 12 12 12 12 + DQT, Row #5: 21 19 12 12 12 12 12 12 + DQT, Row #6: 24 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + ---- + Precision=8 bits + Destination ID=1 (Chrominance, typically) + DQT, Row #0: 13 11 13 16 20 20 17 17 + DQT, Row #1: 11 14 14 14 14 12 12 12 + DQT, Row #2: 13 14 14 14 12 12 12 12 + DQT, Row #3: 16 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + + * Embedded Thumb Marker: SOF + Frame header length = 17 + Precision = 8 + Number of Lines = 160 + Samples per Line = 107 + Image Size = 107 x 160 + + * Embedded Thumb Marker: DRI + Length = 4 + + * Embedded Thumb Marker: DHT + Length = 319 + + * Embedded Thumb Marker: SOS + Skipping scan data + Skipped 1785 bytes + + * Embedded Thumb Marker: EOI + + * Embedded Thumb Signature: 01C2DDA29A1B5DCCD5E217CF9C558A62 + +*** Searching Compression Signatures *** + + Signature: 0165B3F1B409A4D8D5F2ADFFA970D3A5 + Signature (Rotated): 0165B3F1B409A4D8D5F2ADFFA970D3A5 + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: OK [Canon] [Canon EOS 70D] + EXIF Makernotes: NONE + EXIF Software: OK [Adobe Photoshop CS6 (Windows)] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[NIKON ] [E885 ] [FINE ] Yes + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C700UZ ] [ ] Yes + SW :[Adobe Photoshop 7.0 ] [Save As 07 ] + + NOTE: Photoshop IRB detected + NOTE: EXIF Software field recognized as from editor + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/issue750-exif-tranform.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/issue750-exif-tranform.jpg.txt new file mode 100644 index 0000000000..48760626be --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/issue750-exif-tranform.jpg.txt @@ -0,0 +1,435 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\issue750-exif-tranform.jpg] + Filesize: [5587341] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 300 x 300 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 8272 + Identifier = [Exif] + Identifier TIFF = 0x[4D4D002A 00000008] + Endian = Motorola (big) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x000A + [Make ] = "Canon" + [Model ] = "Canon EOS 500D" + [Orientation ] = 1 = Row 0: top, Col 0: left + [DateTime ] = "2017:12:06 15:48:51" + [Artist ] = "" + [YCbCrPositioning ] = Co-sited + [Copyright ] = "" + [ExifOffset ] = @ 0x00B0 + [GPSOffset ] = @ 0x2034 + [XPAuthor ] = "??" + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000CE + Dir Length = 0x0020 + [ExposureTime ] = 1/160 s + [FNumber ] = F9.0 + [ExposureProgram ] = Normal program + [ISOSpeedRatings ] = 3200 + [ExifVersion ] = 02.21 + [DateTimeOriginal ] = "2017:12:06 15:48:51" + [DateTimeDigitized ] = "2017:12:06 15:48:51" + [ComponentsConfiguration ] = [Y Cb Cr .] + [ShutterSpeedValue ] = 483328/65536 + [ApertureValue ] = 417792/65536 + [ExposureBiasValue ] = 1.00 eV + [MeteringMode ] = Pattern + [Flash ] = Flash did not fire + [FocalLength ] = 24 mm + [MakerNote ] = @ 0x028E + [UserComment ] = "" + [SubSecTime ] = "80" + [SubSecTimeOriginal ] = "80" + [SubSecTimeDigitized ] = "80" + [FlashPixVersion ] = 01.00 + [ColorSpace ] = sRGB + [ExifImageWidth ] = 4752 + [ExifImageHeight ] = 3168 + [ExifInteroperabilityOffset ] = @ 0x2010 + [FocalPlaneXResolution ] = 4752000/894 + [FocalPlaneYResolution ] = 3168000/593 + [FocalPlaneResolutionUnit ] = Inch + [CustomRendered ] = Normal process + [ExposureMode ] = Auto exposure + [WhiteBalance ] = Auto white balance + [SceneCaptureType ] = Standard + + EXIF MakerIFD @ Absolute 0x000002AC + Makernote decode option not enabled. + + EXIF GPSIFD @ Absolute 0x00002052 + Dir Length = 0x0001 + [GPSVersionID ] = 2.2.0.0 + + EXIF InteropIFD @ Absolute 0x0000202E + Dir Length = 0x0001 + [InteroperabilityVersion ] = 01.00 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00002066 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 2 3 4 + DQT, Row #1: 1 1 1 1 2 3 4 3 + DQT, Row #2: 1 1 1 1 2 3 4 3 + DQT, Row #3: 1 1 1 2 3 5 5 4 + DQT, Row #4: 1 1 2 3 4 7 6 5 + DQT, Row #5: 1 2 3 4 5 6 7 6 + DQT, Row #6: 3 4 5 5 6 7 7 6 + DQT, Row #7: 4 6 6 6 7 6 6 6 + Approx quality factor = 96.95 (scaling=6.11 variance=1.09) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000020AB + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 1 1 1 3 6 6 6 6 + DQT, Row #1: 1 1 2 4 6 6 6 6 + DQT, Row #2: 1 2 3 6 6 6 6 6 + DQT, Row #3: 3 4 6 6 6 6 6 6 + DQT, Row #4: 6 6 6 6 6 6 6 6 + DQT, Row #5: 6 6 6 6 6 6 6 6 + DQT, Row #6: 6 6 6 6 6 6 6 6 + DQT, Row #7: 6 6 6 6 6 6 6 6 + Approx quality factor = 96.99 (scaling=6.01 variance=0.24) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x000020F0 + Frame header length = 17 + Precision = 8 + Number of Lines = 3168 + Samples per Line = 4752 + Image Size = 4752 x 3168 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002103 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002124 + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000021DB + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000021FC + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000022B3 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000022C1 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0055418B.0 + + Compression stats: + Compression Ratio: 8.10:1 + Bits per pixel: 2.96:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 7852 ( 3%) + # codes of length 03 bits: 194801 ( 83%) + # codes of length 04 bits: 18114 ( 8%) + # codes of length 05 bits: 9703 ( 4%) + # codes of length 06 bits: 3623 ( 2%) + # codes of length 07 bits: 941 ( 0%) + # codes of length 08 bits: 188 ( 0%) + # codes of length 09 bits: 2 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 53609 ( 46%) + # codes of length 03 bits: 36337 ( 31%) + # codes of length 04 bits: 20089 ( 17%) + # codes of length 05 bits: 4404 ( 4%) + # codes of length 06 bits: 2062 ( 2%) + # codes of length 07 bits: 903 ( 1%) + # codes of length 08 bits: 206 ( 0%) + # codes of length 09 bits: 2 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 3801677 ( 49%) + # codes of length 03 bits: 1263986 ( 16%) + # codes of length 04 bits: 1288745 ( 17%) + # codes of length 05 bits: 606891 ( 8%) + # codes of length 06 bits: 282047 ( 4%) + # codes of length 07 bits: 273734 ( 4%) + # codes of length 08 bits: 85749 ( 1%) + # codes of length 09 bits: 90483 ( 1%) + # codes of length 10 bits: 39213 ( 1%) + # codes of length 11 bits: 19089 ( 0%) + # codes of length 12 bits: 6439 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 136 ( 0%) + # codes of length 16 bits: 7545 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 309037 ( 51%) + # codes of length 03 bits: 124353 ( 21%) + # codes of length 04 bits: 87742 ( 14%) + # codes of length 05 bits: 43060 ( 7%) + # codes of length 06 bits: 28928 ( 5%) + # codes of length 07 bits: 2442 ( 0%) + # codes of length 08 bits: 8544 ( 1%) + # codes of length 09 bits: 1150 ( 0%) + # codes of length 10 bits: 376 ( 0%) + # codes of length 11 bits: 126 ( 0%) + # codes of length 12 bits: 30 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 50 ( 0%) + # codes of length 15 bits: 24 ( 0%) + # codes of length 16 bits: 4 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[215] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1016, -3, 3] RGB=[255,255,253] @ MCU[ 92, 26] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x0055418A.7 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0055418B + + +*** Searching Compression Signatures *** + + Signature: 010564D93F295ADB889B91604DC82EE1 + Signature (Rotated): 014302FE54745F4DBB58A0D51CDC66BD + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: OK [Canon] [Canon EOS 500D] + EXIF Makernotes: OK + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[Leica Camera AG ] [M8 Digital Camera ] [ ] No + CAM:[Leica Camera AG ] [M8 Digital Camera ] [ ] No + CAM:[Leica Camera AG ] [M8 Digital Camera ] [ ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5400 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[OLYMPUS CORPORATION ] [C8080WZ ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C40Z,D40Z ] [ ] No + CAM:[Samsung Techwin ] [Digimax V50/a5 ] [ ] No + CAM:[SAMSUNG TECHWIN ] [Pro 815 ] [ ] No + CAM:[SAMSUNG TECHWIN ] [VLUU NV 7, NV 7 ] [ ] No + CAM:[SAMSUNG TECHWIN ] [VLUU NV10, NV10 ] [ ] No + CAM:[SONY ] [CYBERSHOT ] [ ] No + CAM:[SONY ] [DSC-H1 ] [ ] No + CAM:[SONY ] [DSC-H2 ] [ ] No + CAM:[SONY ] [DSC-H5 ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-L1 ] [ ] No + CAM:[SONY ] [DSC-N2 ] [ ] No + CAM:[SONY ] [DSC-P150 ] [ ] No + CAM:[SONY ] [DSC-P200 ] [ ] No + CAM:[SONY ] [DSC-R1 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-V1 ] [ ] No + CAM:[SONY ] [DSC-V3 ] [ ] No + CAM:[SONY ] [DSC-W35 ] [ ] No + CAM:[SONY ] [DSC-W7 ] [ ] No + CAM:[SONY ] [SONY ] [ ] No + SW :[IJG Library ] [097 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [097 ] + SW :[IrfanView ] [097 ] + SW :[idImager ] [097 ] + SW :[FastStone Image Viewer ] [097 ] + SW :[NeatImage ] [097 ] + SW :[Paint.NET ] [097 ] + SW :[Photomatix ] [097 ] + SW :[XnView ] [097 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 4 - Uncertain if processed or original + While the EXIF fields indicate original, no compression signatures + in the current database were found matching this make/model + + Appears to be new signature for known camera. + If the camera/software doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/progressive/JpegSnoopReports/BadEofProgressive.jpg.txt b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/BadEofProgressive.jpg.txt new file mode 100644 index 0000000000..b6a1fe8094 --- /dev/null +++ b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/BadEofProgressive.jpg.txt @@ -0,0 +1,452 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\BadEofProgressive.jpg] + Filesize: [67503] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.2] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x00000014 + Length = 124 + Identifier = [Photoshop 3.0] + 8BIM: [0x0404] Name="" Len=[0x005F] DefinedName="IPTC-NAA record" + IPTC [002:040] Special Instructions = "FBMD2300098903000068210000c735000008450000e88e0000fab00000c6cd000002f80000191a0100653f0100" + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00000092 + Length = 540 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 524 bytes + Preferred CMM Type : 'lcms' (0x6C636D73) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 2012-01-25 03:41:57 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Apple Computer, Inc. ('APPL' (0x4150504C)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : '....' (0x00000000) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'lcms' (0x6C636D73) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000002B0 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 10 16 20 24 + DQT, Row #1: 5 5 6 8 10 23 24 22 + DQT, Row #2: 6 5 6 10 16 23 28 22 + DQT, Row #3: 6 7 9 12 20 35 32 25 + DQT, Row #4: 7 9 15 22 27 44 41 31 + DQT, Row #5: 10 14 22 26 32 42 45 37 + DQT, Row #6: 20 26 31 35 41 48 48 40 + DQT, Row #7: 29 37 38 39 45 40 41 40 + Approx quality factor = 79.94 (scaling=40.12 variance=1.43) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000002F5 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 7 7 10 19 40 40 40 40 + DQT, Row #1: 7 8 10 26 40 40 40 40 + DQT, Row #2: 10 10 22 40 40 40 40 40 + DQT, Row #3: 19 26 40 40 40 40 40 40 + DQT, Row #4: 40 40 40 40 40 40 40 40 + DQT, Row #5: 40 40 40 40 40 40 40 40 + DQT, Row #6: 40 40 40 40 40 40 40 40 + DQT, Row #7: 40 40 40 40 40 40 40 40 + Approx quality factor = 79.87 (scaling=40.26 variance=0.36) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000033A + Frame header length = 17 + Precision = 8 + Number of Lines = 640 + Samples per Line = 640 + Image Size = 640 x 640 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000034D + Huffman table length = 29 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (007 total): 01 02 03 04 05 06 07 + Codes of length 04 bits (001 total): 00 + Codes of length 05 bits (001 total): 08 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 010 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000036C + Huffman table length = 27 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (003 total): 00 03 04 + Codes of length 04 bits (001 total): 05 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000389 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),0(AC) + Component[3]: selector=0x02, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002127 + Huffman table length = 63 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (004 total): 00 02 03 11 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (003 total): 12 21 31 + Codes of length 06 bits (002 total): 05 41 + Codes of length 07 bits (003 total): 13 22 51 + Codes of length 08 bits (004 total): 10 32 61 A1 + Codes of length 09 bits (007 total): 14 20 71 81 91 B1 F0 + Codes of length 10 bits (007 total): 06 23 42 52 C1 D1 E1 + Codes of length 11 bits (002 total): 15 30 + Codes of length 12 bits (005 total): 16 24 33 34 62 + Codes of length 13 bits (005 total): 25 40 50 72 F1 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 044 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002168 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003588 + Huffman table length = 61 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (003 total): 04 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 05 10 13 51 + Codes of length 08 bits (003 total): 14 20 22 + Codes of length 09 bits (005 total): 32 42 61 71 91 + Codes of length 10 bits (007 total): 15 23 33 81 A1 B1 C1 + Codes of length 11 bits (003 total): 06 30 D1 + Codes of length 12 bits (002 total): E1 F0 + Codes of length 13 bits (007 total): 16 24 34 40 43 50 52 + Codes of length 14 bits (001 total): 62 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 042 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000035C7 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000044BF + Huffman table length = 71 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 00 02 03 + Codes of length 04 bits (002 total): 04 11 + Codes of length 05 bits (003 total): 12 21 31 + Codes of length 06 bits (004 total): 13 22 41 51 + Codes of length 07 bits (007 total): 05 10 20 32 61 71 81 + Codes of length 08 bits (005 total): 14 23 42 52 91 + Codes of length 09 bits (005 total): 30 33 62 72 A1 + Codes of length 10 bits (007 total): 15 34 43 53 82 92 B1 + Codes of length 11 bits (003 total): 06 24 40 + Codes of length 12 bits (004 total): 44 A2 C1 D1 + Codes of length 13 bits (001 total): E1 + Codes of length 14 bits (004 total): 25 35 50 F0 + Codes of length 15 bits (003 total): 54 63 73 + Codes of length 16 bits (000 total): + Total number of codes: 052 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00004508 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00008EC5 + Huffman table length = 33 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (000 total): + Codes of length 05 bits (003 total): 10 21 31 + Codes of length 06 bits (001 total): 41 + Codes of length 07 bits (001 total): 51 + Codes of length 08 bits (001 total): 20 + Codes of length 09 bits (001 total): 61 + Codes of length 10 bits (001 total): 71 + Codes of length 11 bits (001 total): 30 + Codes of length 12 bits (001 total): 81 + Codes of length 13 bits (001 total): 40 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 014 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00008EE8 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 10 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000B0CE + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (006 total): 10 41 51 61 71 91 + Codes of length 06 bits (002 total): 20 81 + Codes of length 07 bits (001 total): 30 + Codes of length 08 bits (005 total): 40 A1 B1 C1 F0 + Codes of length 09 bits (001 total): D1 + Codes of length 10 bits (001 total): F1 + Codes of length 11 bits (001 total): E1 + Codes of length 12 bits (001 total): 50 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000B0FA + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 11 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000CDA4 + Huffman table length = 32 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (001 total): 31 + Codes of length 06 bits (001 total): 10 + Codes of length 07 bits (001 total): 41 + Codes of length 08 bits (001 total): 51 + Codes of length 09 bits (001 total): 20 + Codes of length 10 bits (001 total): 61 + Codes of length 11 bits (001 total): 71 + Codes of length 12 bits (001 total): 81 + Codes of length 13 bits (001 total): 91 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 013 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000CDC6 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 10 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000F7DF + Huffman table length = 33 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (002 total): 10 41 + Codes of length 06 bits (003 total): 51 61 71 + Codes of length 07 bits (001 total): 20 + Codes of length 08 bits (001 total): 81 + Codes of length 09 bits (001 total): 30 + Codes of length 10 bits (001 total): 40 + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 014 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000F802 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 11 .. 19 + Successive approximation = 0x10 +ERROR: Ran out of buffer before EOI during phase 1 of Scan decode @ 0x000107B0 + + NOTE: Scan parsing doesn't support this SOF mode. + +ERROR: Early EOF - file may be missing EOI + +*** Searching Compression Signatures *** + + Signature: 01DC499064BA9264D591FDE9071DFD89 + Signature (Rotated): 0175BAF3251040E0EFB2930B73328E7F + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C40Z,D40Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C700UZ ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + SW :[Apple ImageIO.framework ] [050 (Normal) ] + SW :[IJG Library ] [080 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [080 ] + SW :[IrfanView ] [080 ] + SW :[idImager ] [080 ] + SW :[FastStone Image Viewer ] [080 ] + SW :[NeatImage ] [080 ] + SW :[Paint.NET ] [080 ] + SW :[Photomatix ] [080 ] + SW :[XnView ] [080 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/progressive/JpegSnoopReports/ExifUndefType.jpg.txt b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/ExifUndefType.jpg.txt new file mode 100644 index 0000000000..397343c5e5 --- /dev/null +++ b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/ExifUndefType.jpg.txt @@ -0,0 +1,535 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\ExifUndefType.jpg] + Filesize: [6582] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 804 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 86020000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x000002A4 + Dir Length = 0x000C + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [Software ] = "Adobe Photoshop CS4 Windows" + [DateTime ] = "2014:03:28 16:44:10" + [WhitePoint ] = 0/1000000, 0/1000000 + [PrimChromaticities ] = 0/1000000, 0/1000000, 0/1000000, 0/1000000, 0/1000000, 0/1000000 + [YCbCrCoefficients ] = 0/1000000, 0/1000000, 0/1000000 + [YCbCrPositioning ] = 0 + [ReferenceBlackWhite ] = 0/1000000, 0/1000000, 0/1000000, 0/1000000, 0/1000000, 0/1000000 + [ExifOffset ] = @ 0x0138 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x00000156 + Dir Length = 0x001B + [ExposureTime ] = 0/1000000 s + [FNumber ] = F0.0 + [ExposureProgram ] = Not defined + [ISOSpeedRatings ] = 0, 0 + [ExifVersion ] = 12.20 + [CompressedBitsPerPixel ] = 0/1000000 + [ShutterSpeedValue ] = 0/1000000 + [ApertureValue ] = 0/1000000 + [BrightnessValue ] = 0/1000000 + [ExposureBiasValue ] = 0.00 eV + [MaxApertureValue ] = 0/1000000 + [SubjectDistance ] = 0/1000000 + [MeteringMode ] = Unknown + [LightSource ] = unknown + [Flash ] = Flash did not fire + [FocalLength ] = 0 mm + [FlashPixVersion ] = + [ColorSpace ] = sRGB + [ExifImageWidth ] = 850 + [ExifImageHeight ] = 638 + [FocalPlaneXResolution ] = 0/1000000 + [FocalPlaneYResolution ] = 0/1000000 + [FocalPlaneResolutionUnit ] = 0 + [ExposureIndex ] = 0/1000000 + [SensingMethod ] = 0 + [FileSource ] = 0 + [SceneType ] = 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0000033A + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 5 8 10 12 + DQT, Row #1: 2 2 3 4 5 12 12 11 + DQT, Row #2: 3 3 3 5 8 11 14 11 + DQT, Row #3: 3 3 4 6 10 17 16 12 + DQT, Row #4: 4 4 7 11 14 22 21 15 + DQT, Row #5: 5 7 11 13 16 21 23 18 + DQT, Row #6: 10 13 16 17 21 24 24 20 + DQT, Row #7: 14 18 19 20 22 20 21 20 + Approx quality factor = 90.06 (scaling=19.88 variance=1.14) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0000037F + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 3 4 5 9 20 20 20 20 + DQT, Row #1: 4 4 5 13 20 20 20 20 + DQT, Row #2: 5 5 11 20 20 20 20 20 + DQT, Row #3: 9 13 20 20 20 20 20 20 + DQT, Row #4: 20 20 20 20 20 20 20 20 + DQT, Row #5: 20 20 20 20 20 20 20 20 + DQT, Row #6: 20 20 20 20 20 20 20 20 + DQT, Row #7: 20 20 20 20 20 20 20 20 + Approx quality factor = 89.93 (scaling=20.14 variance=0.34) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x000003C4 + Frame header length = 17 + Precision = 8 + Number of Lines = 165 + Samples per Line = 220 + Image Size = 220 x 165 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000003D7 + Huffman table length = 28 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 03 07 + Codes of length 04 bits (003 total): 02 04 05 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 01 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000003F5 + Huffman table length = 22 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (000 total): + Codes of length 05 bits (000 total): + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 003 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000040D + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000581 + Huffman table length = 41 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (006 total): 00 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (003 total): 11 15 16 + Codes of length 06 bits (004 total): 12 13 14 21 + Codes of length 07 bits (002 total): 07 10 + Codes of length 08 bits (002 total): 22 40 + Codes of length 09 bits (003 total): 17 30 60 + Codes of length 10 bits (001 total): 24 + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000005AC + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000883 + Huffman table length = 27 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 11 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 01 10 + Codes of length 05 bits (003 total): 20 30 40 + Codes of length 06 bits (001 total): 50 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000008A0 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000008BF + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 11 + Codes of length 03 bits (001 total): 01 + Codes of length 04 bits (000 total): + Codes of length 05 bits (003 total): 10 21 30 + Codes of length 06 bits (000 total): + Codes of length 07 bits (003 total): 20 40 50 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000008DD + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000905 + Huffman table length = 65 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (004 total): 00 01 02 03 + Codes of length 04 bits (002 total): 04 11 + Codes of length 05 bits (004 total): 12 21 31 34 + Codes of length 06 bits (008 total): 13 32 33 35 91 92 93 D2 + Codes of length 07 bits (009 total): 05 10 14 22 41 51 71 A1 D1 + Codes of length 08 bits (010 total): 20 23 40 42 52 61 81 A2 A3 B1 + Codes of length 09 bits (007 total): 15 24 60 62 72 E1 E2 + Codes of length 10 bits (001 total): 30 + Codes of length 11 bits (001 total): B2 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 046 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000948 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000E49 + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (002 total): 31 41 + Codes of length 06 bits (004 total): 51 61 71 D1 + Codes of length 07 bits (006 total): 81 91 A1 C1 F0 F1 + Codes of length 08 bits (002 total): 40 B1 + Codes of length 09 bits (003 total): 10 20 60 + Codes of length 10 bits (001 total): 30 + Codes of length 11 bits (001 total): E1 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000E75 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001266 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000012E8 + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 11 + Codes of length 03 bits (001 total): 10 + Codes of length 04 bits (000 total): + Codes of length 05 bits (002 total): 30 51 + Codes of length 06 bits (003 total): 21 40 50 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001306 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000133E + Huffman table length = 30 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (003 total): 10 30 51 + Codes of length 05 bits (000 total): + Codes of length 06 bits (002 total): 20 61 + Codes of length 07 bits (003 total): 21 40 50 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 011 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000135E + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000139C + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 00 21 + Codes of length 05 bits (001 total): 31 + Codes of length 06 bits (003 total): 41 51 61 + Codes of length 07 bits (003 total): 71 81 B1 + Codes of length 08 bits (003 total): 91 A1 D1 + Codes of length 09 bits (004 total): 10 40 E1 F0 + Codes of length 10 bits (003 total): 20 C1 F1 + Codes of length 11 bits (001 total): 60 + Codes of length 12 bits (001 total): 30 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000013C8 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x000019B4 + + +*** Searching Compression Signatures *** + + Signature: 013BA18D5561625796E986FDBC09F846 + Signature (Rotated): 01AC57E12793DFA7C46C704625C5AF0F + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: OK [Adobe Photoshop CS4 Windows] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[??? ] [Treo 680 ] [ ] Yes + CAM:[Canon ] [Canon PowerShot Pro1 ] [fine ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E3100 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5000 ] [FINE ] No + CAM:[NIKON ] [E5700 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[NIKON ] [E885 ] [FINE ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 9530 ] [Superfine ] Yes + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-W1 ] [ ] No + CAM:[SONY ] [SONY ] [ ] No + SW :[ACDSee ] [ ] + SW :[FixFoto ] [fine ] + SW :[IJG Library ] [090 ] + SW :[ZoomBrowser EX ] [high ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [090 ] + SW :[IrfanView ] [090 ] + SW :[idImager ] [090 ] + SW :[FastStone Image Viewer ] [090 ] + SW :[NeatImage ] [090 ] + SW :[Paint.NET ] [090 ] + SW :[Photomatix ] [090 ] + SW :[XnView ] [090 ] + + NOTE: EXIF Software field recognized as from editor + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + Appears to be new signature for known software. + If the camera/software doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/progressive/JpegSnoopReports/Festzug.jpg.txt b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/Festzug.jpg.txt new file mode 100644 index 0000000000..445e80a7e7 --- /dev/null +++ b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/Festzug.jpg.txt @@ -0,0 +1,459 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Festzug.jpg] + Filesize: [49977] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 229 x 229 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 131 + ---- + Precision=16 bits + Destination ID=0 (Luminance) + DQT, Row #0: 53 37 33 53 80 133 170 203 + DQT, Row #1: 40 40 47 63 87 193 200 183 + DQT, Row #2: 47 43 53 80 133 190 230 186 + DQT, Row #3: 47 57 73 97 170 290 266 206 + DQT, Row #4: 60 73 123 186 226 363 343 256 + DQT, Row #5: 80 117 183 213 270 346 376 306 + DQT, Row #6: 163 213 260 290 343 403 400 336 + DQT, Row #7: 240 306 316 326 373 333 343 330 + Approx quality factor = 15.01 (scaling=333.00 variance=1.25) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000099 + Table length = 131 + ---- + Precision=16 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 57 60 80 157 330 330 330 330 + DQT, Row #1: 60 70 87 220 330 330 330 330 + DQT, Row #2: 80 87 186 330 330 330 330 330 + DQT, Row #3: 157 220 330 330 330 330 330 330 + DQT, Row #4: 330 330 330 330 330 330 330 330 + DQT, Row #5: 330 330 330 330 330 330 330 330 + DQT, Row #6: 330 330 330 330 330 330 330 330 + DQT, Row #7: 330 330 330 330 330 330 330 330 + Approx quality factor = 15.00 (scaling=333.41 variance=0.14) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000011E + Frame header length = 17 + Precision = 8 + Number of Lines = 1071 + Samples per Line = 1443 + Image Size = 1443 x 1071 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000131 + Huffman table length = 25 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 006 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000014C + Huffman table length = 22 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (000 total): + Codes of length 05 bits (000 total): + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 003 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000164 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000028E0 + Huffman table length = 38 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (004 total): 02 10 20 30 + Codes of length 05 bits (003 total): 12 31 40 + Codes of length 06 bits (000 total): + Codes of length 07 bits (003 total): 21 41 50 + Codes of length 08 bits (001 total): 60 + Codes of length 09 bits (001 total): 03 + Codes of length 10 bits (000 total): + Codes of length 11 bits (003 total): 22 32 42 + Codes of length 12 bits (001 total): 13 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 019 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002908 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003D97 + Huffman table length = 29 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (003 total): 00 10 11 + Codes of length 04 bits (001 total): 20 + Codes of length 05 bits (000 total): + Codes of length 06 bits (002 total): 30 60 + Codes of length 07 bits (003 total): 80 90 C0 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 010 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003DB6 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003DE1 + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 10 11 + Codes of length 04 bits (003 total): 00 20 60 + Codes of length 05 bits (000 total): + Codes of length 06 bits (003 total): 80 90 C0 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003DFF + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003E21 + Huffman table length = 23 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 21 + Codes of length 02 bits (001 total): D0 + Codes of length 03 bits (001 total): A0 + Codes of length 04 bits (001 total): B0 + Codes of length 05 bits (000 total): + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 004 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003E3A + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003E4C + Huffman table length = 36 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 10 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (003 total): 20 30 41 + Codes of length 06 bits (000 total): + Codes of length 07 bits (003 total): 40 50 51 + Codes of length 08 bits (001 total): 61 + Codes of length 09 bits (001 total): 60 + Codes of length 10 bits (001 total): 71 + Codes of length 11 bits (001 total): 81 + Codes of length 12 bits (001 total): B1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 017 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003E72 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00006325 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00007512 + Huffman table length = 30 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (003 total): 10 21 60 + Codes of length 05 bits (001 total): 31 + Codes of length 06 bits (000 total): + Codes of length 07 bits (003 total): 20 41 80 + Codes of length 08 bits (001 total): C0 + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 011 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00007532 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000075CE + Huffman table length = 30 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 11 + Codes of length 03 bits (001 total): 10 + Codes of length 04 bits (000 total): + Codes of length 05 bits (003 total): 21 31 60 + Codes of length 06 bits (001 total): 41 + Codes of length 07 bits (000 total): + Codes of length 08 bits (003 total): 20 80 C0 + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 011 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000075EE + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00007676 + Huffman table length = 43 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (000 total): + Codes of length 05 bits (002 total): 21 31 + Codes of length 06 bits (002 total): 10 41 + Codes of length 07 bits (002 total): 20 51 + Codes of length 08 bits (002 total): 30 61 + Codes of length 09 bits (003 total): 40 50 71 + Codes of length 10 bits (000 total): + Codes of length 11 bits (003 total): 60 81 91 + Codes of length 12 bits (001 total): A1 + Codes of length 13 bits (001 total): B1 + Codes of length 14 bits (000 total): + Codes of length 15 bits (002 total): C1 D1 + Codes of length 16 bits (003 total): E1 F0 F1 + Total number of codes: 024 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000076A3 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000C337 + + +*** Searching Compression Signatures *** + + Signature: 0105A3D95D2D36DE9351313E30D8E945 + Signature (Rotated): 013C3A43642D2E8325A76C3818B3C324 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[IJG Library ] [015 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [015 ] + SW :[IrfanView ] [015 ] + SW :[idImager ] [015 ] + SW :[FastStone Image Viewer ] [015 ] + SW :[NeatImage ] [015 ] + SW :[Paint.NET ] [015 ] + SW :[Photomatix ] [015 ] + SW :[XnView ] [015 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/progressive/JpegSnoopReports/fb.jpg.txt b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/fb.jpg.txt new file mode 100644 index 0000000000..6f20fc1ee8 --- /dev/null +++ b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/fb.jpg.txt @@ -0,0 +1,525 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\fb.jpg] + Filesize: [15787] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.2] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: COM (Comment) (xFFFE) *** + OFFSET: 0x00000014 + Comment length = 4 + Comment=*. + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0000001A + Length = 540 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 524 bytes + Preferred CMM Type : 'lcms' (0x6C636D73) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 2012-01-25 03:41:57 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Apple Computer, Inc. ('APPL' (0x4150504C)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : '....' (0x00000000) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'lcms' (0x6C636D73) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000238 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 8 6 5 8 12 20 26 31 + DQT, Row #1: 6 6 7 10 13 29 30 28 + DQT, Row #2: 7 7 8 12 20 29 35 28 + DQT, Row #3: 7 9 11 15 26 44 40 31 + DQT, Row #4: 9 11 19 28 34 55 52 39 + DQT, Row #5: 12 18 28 32 41 52 57 46 + DQT, Row #6: 25 32 39 44 52 61 60 51 + DQT, Row #7: 36 46 48 49 56 50 52 50 + Approx quality factor = 74.75 (scaling=50.51 variance=0.81) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0000027D + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + Approx quality factor = 74.74 (scaling=50.52 variance=0.19) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x000002C2 + Frame header length = 17 + Precision = 8 + Number of Lines = 336 + Samples per Line = 276 + Image Size = 276 x 336 + Raw Image Orientation = Portrait + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000002D5 + Huffman table length = 27 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 04 + Codes of length 03 bits (005 total): 00 02 03 05 06 + Codes of length 04 bits (001 total): 01 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000002F2 + Huffman table length = 24 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 03 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (000 total): + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 005 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000030C + Huffman table length = 24 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 03 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (000 total): + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 005 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000326 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000935 + Huffman table length = 43 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 02 03 + Codes of length 03 bits (002 total): 01 04 + Codes of length 04 bits (001 total): 00 + Codes of length 05 bits (002 total): 11 12 + Codes of length 06 bits (006 total): 05 10 13 20 31 32 + Codes of length 07 bits (002 total): 21 33 + Codes of length 08 bits (002 total): 14 22 + Codes of length 09 bits (002 total): 34 41 + Codes of length 10 bits (003 total): 15 23 30 + Codes of length 11 bits (001 total): 24 + Codes of length 12 bits (001 total): 42 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 024 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000962 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000012EE + Huffman table length = 39 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 10 + Codes of length 05 bits (004 total): 03 20 21 31 + Codes of length 06 bits (001 total): 12 + Codes of length 07 bits (004 total): 13 30 41 51 + Codes of length 08 bits (001 total): 22 + Codes of length 09 bits (005 total): 32 40 42 50 61 + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 020 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001317 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000142A + Huffman table length = 36 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 10 + Codes of length 05 bits (004 total): 03 20 21 31 + Codes of length 06 bits (002 total): 12 30 + Codes of length 07 bits (002 total): 13 41 + Codes of length 08 bits (003 total): 22 40 51 + Codes of length 09 bits (001 total): 50 + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 017 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001450 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000155A + Huffman table length = 51 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 02 + Codes of length 04 bits (003 total): 03 10 11 + Codes of length 05 bits (006 total): 12 20 21 31 41 51 + Codes of length 06 bits (005 total): 22 32 61 71 81 + Codes of length 07 bits (002 total): 13 30 + Codes of length 08 bits (005 total): 04 33 42 72 91 + Codes of length 09 bits (004 total): 14 52 62 A1 + Codes of length 10 bits (003 total): 23 82 B1 + Codes of length 11 bits (001 total): 43 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 032 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000158F + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00001D3E + Huffman table length = 40 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 11 21 + Codes of length 04 bits (001 total): 31 + Codes of length 05 bits (003 total): 10 41 51 + Codes of length 06 bits (004 total): 20 61 71 A1 + Codes of length 07 bits (002 total): 81 91 + Codes of length 08 bits (002 total): B1 F0 + Codes of length 09 bits (003 total): 30 C1 D1 + Codes of length 10 bits (001 total): E1 + Codes of length 11 bits (001 total): F1 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 021 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001D68 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000028B9 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000029E4 + Huffman table length = 32 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (000 total): + Codes of length 05 bits (003 total): 10 21 31 + Codes of length 06 bits (000 total): + Codes of length 07 bits (003 total): 20 41 51 + Codes of length 08 bits (001 total): 30 + Codes of length 09 bits (001 total): 61 + Codes of length 10 bits (001 total): 40 + Codes of length 11 bits (001 total): 50 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 013 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002A06 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002B55 + Huffman table length = 32 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (003 total): 10 21 31 + Codes of length 05 bits (001 total): 20 + Codes of length 06 bits (001 total): 41 + Codes of length 07 bits (000 total): + Codes of length 08 bits (003 total): 30 51 61 + Codes of length 09 bits (001 total): 71 + Codes of length 10 bits (001 total): 40 + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 013 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002B77 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002CEA + Huffman table length = 40 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (003 total): 31 41 51 + Codes of length 06 bits (003 total): 10 61 71 + Codes of length 07 bits (004 total): 81 91 A1 B1 + Codes of length 08 bits (003 total): 20 C1 F0 + Codes of length 09 bits (001 total): D1 + Codes of length 10 bits (001 total): E1 + Codes of length 11 bits (001 total): F1 + Codes of length 12 bits (001 total): 30 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 021 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002D14 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00003DA9 + + +*** Searching Compression Signatures *** + + Signature: 0182408A81A4ABF04D4A34A8A5E98C58 + Signature (Rotated): 012D821C6AB210E2A753BE053B8F55D0 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[SONY ] [CYBERSHOT U ] [ ] Yes + SW :[Adobe Photoshop 7.0 ] [Save As 07 ] + SW :[Apple Quicktime ] [0466-0467 ] + SW :[Digital Photo Professiona] [05 ] + SW :[IJG Library ] [075 ] + SW :[MS Paint ] [ ] + SW :[MS Visio ] [ ] + SW :[ZoomBrowser EX ] [low ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [075 ] + SW :[IrfanView ] [075 ] + SW :[idImager ] [075 ] + SW :[FastStone Image Viewer ] [075 ] + SW :[NeatImage ] [075 ] + SW :[Paint.NET ] [075 ] + SW :[Photomatix ] [075 ] + SW :[XnView ] [075 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/progressive/JpegSnoopReports/progress.jpg.txt b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/progress.jpg.txt new file mode 100644 index 0000000000..f38a115328 --- /dev/null +++ b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/progress.jpg.txt @@ -0,0 +1,468 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\progress.jpg] + Filesize: [44884] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 5 3 3 5 7 12 15 18 + DQT, Row #1: 4 4 4 6 8 17 18 17 + DQT, Row #2: 4 4 5 7 12 17 21 17 + DQT, Row #3: 4 5 7 9 15 26 24 19 + DQT, Row #4: 5 7 11 17 20 33 31 23 + DQT, Row #5: 7 11 17 19 24 31 34 28 + DQT, Row #6: 15 19 23 26 31 36 36 30 + DQT, Row #7: 22 28 29 29 34 30 31 30 + Approx quality factor = 84.93 (scaling=30.13 variance=1.05) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 5 5 7 14 30 30 30 30 + DQT, Row #1: 5 6 8 20 30 30 30 30 + DQT, Row #2: 7 8 17 30 30 30 30 30 + DQT, Row #3: 14 20 30 30 30 30 30 30 + DQT, Row #4: 30 30 30 30 30 30 30 30 + DQT, Row #5: 30 30 30 30 30 30 30 30 + DQT, Row #6: 30 30 30 30 30 30 30 30 + DQT, Row #7: 30 30 30 30 30 30 30 30 + Approx quality factor = 84.93 (scaling=30.15 variance=0.29) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 486 + Samples per Line = 341 + Image Size = 341 x 486 + Raw Image Orientation = Portrait + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 28 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 04 + Codes of length 03 bits (005 total): 01 02 03 05 06 + Codes of length 04 bits (001 total): 00 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000CF + Huffman table length = 26 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 02 03 + Codes of length 03 bits (003 total): 00 01 04 + Codes of length 04 bits (001 total): 05 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 007 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000EB + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000CCC + Huffman table length = 45 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (002 total): 00 03 + Codes of length 04 bits (002 total): 04 11 + Codes of length 05 bits (001 total): 12 + Codes of length 06 bits (003 total): 05 13 21 + Codes of length 07 bits (003 total): 10 22 31 + Codes of length 08 bits (004 total): 14 20 32 41 + Codes of length 09 bits (002 total): 06 23 + Codes of length 10 bits (002 total): 30 33 + Codes of length 11 bits (003 total): 15 24 42 + Codes of length 12 bits (001 total): 34 + Codes of length 13 bits (001 total): 43 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 026 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000CFB + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000020DC + Huffman table length = 46 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 03 + Codes of length 04 bits (001 total): 11 + Codes of length 05 bits (004 total): 04 10 21 31 + Codes of length 06 bits (001 total): 12 + Codes of length 07 bits (003 total): 13 20 41 + Codes of length 08 bits (003 total): 05 22 51 + Codes of length 09 bits (003 total): 23 32 61 + Codes of length 10 bits (005 total): 14 30 33 42 71 + Codes of length 11 bits (000 total): + Codes of length 12 bits (003 total): 15 52 91 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 027 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000210C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002604 + Huffman table length = 41 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (002 total): 03 10 + Codes of length 05 bits (002 total): 21 31 + Codes of length 06 bits (002 total): 12 20 + Codes of length 07 bits (001 total): 13 + Codes of length 08 bits (004 total): 04 22 41 61 + Codes of length 09 bits (002 total): 42 51 + Codes of length 10 bits (002 total): 14 32 + Codes of length 11 bits (003 total): 33 71 F0 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000262F + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000029A7 + Huffman table length = 61 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 00 02 11 + Codes of length 04 bits (003 total): 03 12 21 + Codes of length 05 bits (001 total): 31 + Codes of length 06 bits (005 total): 10 22 41 51 61 + Codes of length 07 bits (006 total): 04 13 20 32 71 81 + Codes of length 08 bits (005 total): 23 30 42 52 91 + Codes of length 09 bits (002 total): A1 B1 + Codes of length 10 bits (004 total): 62 72 C1 F0 + Codes of length 11 bits (006 total): 14 33 40 82 D1 E1 + Codes of length 12 bits (001 total): 24 + Codes of length 13 bits (005 total): 05 43 53 73 F1 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 042 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000029E6 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003FF3 + Huffman table length = 39 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (002 total): 41 51 + Codes of length 06 bits (001 total): 61 + Codes of length 07 bits (003 total): 71 81 91 + Codes of length 08 bits (004 total): 10 A1 B1 C1 + Codes of length 09 bits (003 total): D1 E1 F0 + Codes of length 10 bits (001 total): 20 + Codes of length 11 bits (001 total): F1 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 020 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000401C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00006299 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000064A9 + Huffman table length = 39 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (003 total): 31 41 51 + Codes of length 06 bits (003 total): 10 61 71 + Codes of length 07 bits (004 total): 81 91 D1 F0 + Codes of length 08 bits (003 total): A1 B1 E1 + Codes of length 09 bits (001 total): C1 + Codes of length 10 bits (001 total): F1 + Codes of length 11 bits (001 total): 20 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 020 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000064D2 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00006ACB + Huffman table length = 38 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (000 total): + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (002 total): 10 51 + Codes of length 08 bits (001 total): 61 + Codes of length 09 bits (003 total): 91 D1 F0 + Codes of length 10 bits (005 total): 71 81 A1 B1 C1 + Codes of length 11 bits (001 total): 20 + Codes of length 12 bits (001 total): E1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 019 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00006AF3 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00006F95 + Huffman table length = 38 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 00 21 + Codes of length 05 bits (002 total): 31 41 + Codes of length 06 bits (002 total): 51 61 + Codes of length 07 bits (002 total): 71 81 + Codes of length 08 bits (002 total): 91 A1 + Codes of length 09 bits (002 total): B1 F0 + Codes of length 10 bits (003 total): C1 D1 E1 + Codes of length 11 bits (001 total): F1 + Codes of length 12 bits (001 total): 10 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 019 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00006FBD + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000AF52 + + +*** Searching Compression Signatures *** + + Signature: 0155D875C95B74D0F3C5835A62516F48 + Signature (Rotated): 01D38A25358EB7649A254E19F1D46600 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[Nokia ] [N73 ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 8100 ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + SW :[IJG Library ] [085 ] + SW :[Picasa ] [085 (Normal) ] + SW :[ZoomBrowser EX ] [medium ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [085 ] + SW :[IrfanView ] [085 ] + SW :[idImager ] [085 ] + SW :[FastStone Image Viewer ] [085 ] + SW :[NeatImage ] [085 ] + SW :[Paint.NET ] [085 ] + SW :[Photomatix ] [085 ] + SW :[XnView ] [085 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + From cfb9c61b6cfdbdfb41d7c10e2e6ca43f8dba8300 Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Sat, 3 Nov 2018 19:24:30 -0500 Subject: [PATCH 284/381] 762: added AoT method to pre-seed dithering engine --- src/ImageSharp/Formats/Gif/ImageExtensions.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/ImageSharp/Formats/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs index b226201082..2c5496f528 100644 --- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs @@ -5,6 +5,8 @@ using System.IO; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Primitives; +using SixLabors.ImageSharp.Processing.Processors.Dithering; using SixLabors.ImageSharp.Processing.Processors.Quantization; namespace SixLabors.ImageSharp @@ -54,5 +56,17 @@ namespace SixLabors.ImageSharp var test = new OctreeFrameQuantizer(new OctreeQuantizer(false)); test.AotGetPalette(); } + + /// + /// This method pre-seeds the default FloydSteinbergDiffuser in the AoT compiler for iOS. + /// + /// The pixel format. + public static void AotCompileDithering() + where TPixel : struct, IPixel + { + var test = new FloydSteinbergDiffuser(); + TPixel pixel = default; + test.Dither(new ImageFrame(Configuration.Default, 1, 1), pixel, pixel, 0, 0, 0, 0, 0, 0); + } } } From 78070dcc8928561f21f3aa5d59bdcc808ac951ec Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Sat, 3 Nov 2018 19:36:47 -0500 Subject: [PATCH 285/381] 762: added AoT method to pre-seed WuQuantizer --- src/ImageSharp/Formats/Gif/ImageExtensions.cs | 14 +++++++++++++- .../Quantization/WuFrameQuantizer{TPixel}.cs | 2 ++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs index 2c5496f528..f1c2ae5fb5 100644 --- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs @@ -58,7 +58,19 @@ namespace SixLabors.ImageSharp } /// - /// This method pre-seeds the default FloydSteinbergDiffuser in the AoT compiler for iOS. + /// This method pre-seeds the WuQuantizer in the AoT compiler for iOS. + /// + /// The pixel format. + public static void AotCompileWuQuantizer() + where TPixel : struct, IPixel + { + var test = new WuFrameQuantizer(new WuQuantizer(false)); + test.QuantizeFrame(new ImageFrame(Configuration.Default, 1, 1)); + test.AotGetPalette(); + } + + /// + /// This method pre-seeds the default dithering engine (FloydSteinbergDiffuser) in the AoT compiler for iOS. /// /// The pixel format. public static void AotCompileDithering() diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 43d22597df..44df226cfd 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -173,6 +173,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } } + internal TPixel[] AotGetPalette() => this.GetPalette(); + /// protected override TPixel[] GetPalette() { From 8c6903873bc4c48ddc2e933c82a73e2510aaf9f4 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 01:53:21 +0100 Subject: [PATCH 286/381] improved benchmarks + more benchmark results --- .../Common/Helpers/InliningOptions.cs | 2 +- .../Codecs/Jpeg/DecodeJpeg.cs | 89 ------------- .../Codecs/Jpeg/DecodeJpegMultiple.cs | 18 ++- .../Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs | 125 ++++++++++++++++++ .../Codecs/Jpeg/LoadResizeSave.cs | 2 +- .../Codecs/Jpeg/LoadResizeSave_MultiImage.cs | 88 ++++++++++++ .../Codecs/MultiImageBenchmarkBase.cs | 30 ++++- .../ProfilingBenchmarks/JpegBenchmarks.cs | 56 ++++---- tests/ImageSharp.Tests/TestImages.cs | 13 ++ 9 files changed, 294 insertions(+), 129 deletions(-) delete mode 100644 tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs create mode 100644 tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs create mode 100644 tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_MultiImage.cs diff --git a/src/ImageSharp/Common/Helpers/InliningOptions.cs b/src/ImageSharp/Common/Helpers/InliningOptions.cs index ad85c4fc81..069a426d75 100644 --- a/src/ImageSharp/Common/Helpers/InliningOptions.cs +++ b/src/ImageSharp/Common/Helpers/InliningOptions.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// Uncomment this for verbose profiler results: +// Uncomment this for verbose profiler results. DO NOT PUSH TO MAIN! // #define PROFILING using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs deleted file mode 100644 index 57dcede88d..0000000000 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Drawing; -using System.IO; -using BenchmarkDotNet.Attributes; - -using SixLabors.ImageSharp.Formats.Jpeg; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Tests; -using CoreSize = SixLabors.Primitives.Size; -using SDImage = System.Drawing.Image; - -namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg -{ - [Config(typeof(Config.ShortClr))] - public class DecodeJpeg - { - private byte[] jpegBytes; - - private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); - - [Params(TestImages.Jpeg.Baseline.Jpeg420Exif - //, TestImages.Jpeg.Baseline.Calliphora - )] - public string TestImage { get; set; } - - [GlobalSetup] - public void ReadImages() - { - if (this.jpegBytes == null) - { - this.jpegBytes = File.ReadAllBytes(this.TestImageFullPath); - } - } - - [Benchmark(Baseline = true, Description = "Decode Jpeg - System.Drawing")] - public Size JpegSystemDrawing() - { - using (var memoryStream = new MemoryStream(this.jpegBytes)) - { - using (var image = SDImage.FromStream(memoryStream)) - { - return image.Size; - } - } - } - - [Benchmark(Description = "Decode Jpeg - ImageSharp")] - public CoreSize JpegImageSharp() - { - using (var memoryStream = new MemoryStream(this.jpegBytes)) - { - using (var image = Image.Load(memoryStream, new JpegDecoder())) - { - return new CoreSize(image.Width, image.Height); - } - } - } - - // RESULTS (2018 October): - // - // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 - // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores - // Frequency=2742191 Hz, Resolution=364.6719 ns, Timer=TSC - // .NET Core SDK=2.1.403 - // [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT - // Job-MCUBGX : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 - // Job-TZIRPF : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT - // - // - // Method | Runtime | TestImage | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | - // ------------------------------- |-------- |----------------------------- |---------:|----------:|----------:|-------:|---------:|---------:|----------:| - // 'Decode Jpeg - System.Drawing' | Clr | Jpg/baseline/jpeg420exif.jpg | 17.10 ms | 4.720 ms | 0.2667 ms | 1.00 | 0.00 | 218.7500 | 757.88 KB | - // 'Decode Jpeg - ImageSharp' | Clr | Jpg/baseline/jpeg420exif.jpg | 57.77 ms | 4.626 ms | 0.2614 ms | 3.38 | 0.04 | 125.0000 | 566.01 KB | - // | | | | | | | | | | - // 'Decode Jpeg - System.Drawing' | Core | Jpg/baseline/jpeg420exif.jpg | 17.45 ms | 2.092 ms | 0.1182 ms | 1.00 | 0.00 | 218.7500 | 757.04 KB | - // 'Decode Jpeg - ImageSharp' | Core | Jpg/baseline/jpeg420exif.jpg | 48.39 ms | 14.562 ms | 0.8228 ms | 2.77 | 0.04 | 125.0000 | 529.96 KB | - - // RESULTS (2018 November 1): - // Method | Runtime | TestImage | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | - // ------------------------------- |-------- |----------------------------- |---------:|----------:|----------:|-------:|---------:|---------:|----------:| - // 'Decode Jpeg - System.Drawing' | Clr | Jpg/baseline/jpeg420exif.jpg | 17.59 ms | 4.611 ms | 0.2605 ms | 1.00 | 0.00 | 218.7500 | 757.88 KB | - // 'Decode Jpeg - ImageSharp' | Clr | Jpg/baseline/jpeg420exif.jpg | 55.33 ms | 2.133 ms | 0.1205 ms | 3.15 | 0.04 | 125.0000 | 566.01 KB | - // | | | | | | | | | | - // 'Decode Jpeg - System.Drawing' | Core | Jpg/baseline/jpeg420exif.jpg | 17.83 ms | 24.326 ms | 1.3745 ms | 1.00 | 0.00 | 218.7500 | 757.04 KB | - // 'Decode Jpeg - ImageSharp' | Core | Jpg/baseline/jpeg420exif.jpg | 44.93 ms | 3.088 ms | 0.1745 ms | 2.53 | 0.15 | 125.0000 | 529.96 KB | - } -} diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs index be0fe76b82..53459e3c45 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs @@ -2,23 +2,27 @@ // Licensed under the Apache License, Version 2.0. using System.Collections.Generic; + using BenchmarkDotNet.Attributes; + using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests; + using SDImage = System.Drawing.Image; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { - [Config(typeof(Config.ShortClr))] + /// + /// An expensive Jpeg benchmark, running on a wide range of input images, showing aggregate results. + /// + [Config(typeof(MultiImageBenchmarkBase.Config))] public class DecodeJpegMultiple : MultiImageBenchmarkBase { - protected override IEnumerable InputImageSubfoldersOrFiles => new[] - { - "Jpg/baseline", - "Jpg/progressive", - }; + protected override IEnumerable InputImageSubfoldersOrFiles => TestImages.Jpeg.BenchmarkSuite; - protected override IEnumerable SearchPatterns => new[] { "*.jpg" }; + [Params(InputImageCategory.AllImages)] + public override InputImageCategory InputCategory { get; set; } [Benchmark(Description = "DecodeJpegMultiple - ImageSharp")] public void DecodeJpegImageSharp() diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs new file mode 100644 index 0000000000..e161bca05b --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs @@ -0,0 +1,125 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Drawing; +using System.IO; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Jobs; + +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests; +using CoreSize = SixLabors.Primitives.Size; +using SDImage = System.Drawing.Image; +// ReSharper disable InconsistentNaming + +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg +{ + /// + /// Image-specific Jpeg benchmarks + /// + [Config(typeof(Config.ShortClr))] + public class DecodeJpeg_ImageSpecific + { + public class Config : ManualConfig + { + public Config() + { + // Uncomment if you want to use any of the diagnoser + this.Add(new BenchmarkDotNet.Diagnosers.MemoryDiagnoser()); + } + + public class ShortClr : Benchmarks.Config + { + public ShortClr() + { + this.Add( + //Job.Clr.WithLaunchCount(1).WithWarmupCount(2).WithTargetCount(3), + Job.Core.WithLaunchCount(1).WithWarmupCount(2).WithTargetCount(3) + ); + } + } + } + + private byte[] jpegBytes; + + private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); + + [Params( + TestImages.Jpeg.Baseline.Lake, + TestImages.Jpeg.Issues.BadRstProgressive518, + TestImages.Jpeg.Issues.ExifGetString750Transform, + + TestImages.Jpeg.Baseline.Jpeg420Exif + )] + public string TestImage { get; set; } + + [GlobalSetup] + public void ReadImages() + { + if (this.jpegBytes == null) + { + this.jpegBytes = File.ReadAllBytes(this.TestImageFullPath); + } + } + + [Benchmark(Baseline = true, Description = "Decode Jpeg - System.Drawing")] + public Size JpegSystemDrawing() + { + using (var memoryStream = new MemoryStream(this.jpegBytes)) + { + using (var image = SDImage.FromStream(memoryStream)) + { + return image.Size; + } + } + } + + [Benchmark(Description = "Decode Jpeg - ImageSharp")] + public CoreSize JpegImageSharp() + { + using (var memoryStream = new MemoryStream(this.jpegBytes)) + { + using (var image = Image.Load(memoryStream, new JpegDecoder(){ IgnoreMetadata = true})) + { + return new CoreSize(image.Width, image.Height); + } + } + } + + // RESULTS (2018 October 31): + // + // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 + // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores + // Frequency=2742191 Hz, Resolution=364.6719 ns, Timer=TSC + // .NET Core SDK=2.1.403 + // [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // Job-MCUBGX : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 + // Job-TZIRPF : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // + // + // Method | Runtime | TestImage | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ------------------------------- |-------- |----------------------------- |---------:|----------:|----------:|-------:|---------:|---------:|----------:| + // 'Decode Jpeg - System.Drawing' | Clr | Jpg/baseline/jpeg420exif.jpg | 17.10 ms | 4.720 ms | 0.2667 ms | 1.00 | 0.00 | 218.7500 | 757.88 KB | + // 'Decode Jpeg - ImageSharp' | Clr | Jpg/baseline/jpeg420exif.jpg | 57.77 ms | 4.626 ms | 0.2614 ms | 3.38 | 0.04 | 125.0000 | 566.01 KB | + // | | | | | | | | | | + // 'Decode Jpeg - System.Drawing' | Core | Jpg/baseline/jpeg420exif.jpg | 17.45 ms | 2.092 ms | 0.1182 ms | 1.00 | 0.00 | 218.7500 | 757.04 KB | + // 'Decode Jpeg - ImageSharp' | Core | Jpg/baseline/jpeg420exif.jpg | 48.39 ms | 14.562 ms | 0.8228 ms | 2.77 | 0.04 | 125.0000 | 529.96 KB | + + // RESULTS (2018 November 4): + // Method | TestImage | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Gen 1 | Gen 2 | Allocated | + // ------------------------------- |-------------------------------------------- |-----------:|-----------:|----------:|-------:|---------:|----------:|---------:|---------:|------------:| + // 'Decode Jpeg - System.Drawing' | Jpg/baseline/Lake.jpg | 6.291 ms | 1.200 ms | 0.0678 ms | 1.00 | 0.00 | 62.5000 | - | - | 205.83 KB | + // 'Decode Jpeg - ImageSharp' | Jpg/baseline/Lake.jpg | 18.493 ms | 3.025 ms | 0.1709 ms | 2.94 | 0.03 | - | - | - | 19.97 KB | + // | | | | | | | | | | | + // 'Decode Jpeg - System.Drawing' | Jpg/baseline/jpeg420exif.jpg | 16.962 ms | 1.446 ms | 0.0817 ms | 1.00 | 0.00 | 218.7500 | - | - | 757.04 KB | + // 'Decode Jpeg - ImageSharp' | Jpg/baseline/jpeg420exif.jpg | 42.105 ms | 4.496 ms | 0.2540 ms | 2.48 | 0.02 | - | - | - | 21.94 KB | + // | | | | | | | | | | | + // 'Decode Jpeg - System.Drawing' | Jpg/issues/Issue518-Bad-RST-Progressive.jpg | 432.344 ms | 89.746 ms | 5.0708 ms | 1.00 | 0.00 | 2375.0000 | - | - | 7403.76 KB | + // 'Decode Jpeg - ImageSharp' | Jpg/issues/Issue518-Bad-RST-Progressive.jpg | 421.292 ms | 128.587 ms | 7.2654 ms | 0.97 | 0.02 | 125.0000 | 125.0000 | 125.0000 | 35186.98 KB | + // | | | | | | | | | | | + // 'Decode Jpeg - System.Drawing' | Jpg/issues/issue750-exif-tranform.jpg | 94.723 ms | 4.663 ms | 0.2635 ms | 1.00 | 0.00 | 1750.0000 | - | - | 5492.63 KB | + // 'Decode Jpeg - ImageSharp' | Jpg/issues/issue750-exif-tranform.jpg | 234.071 ms | 37.979 ms | 2.1459 ms | 2.47 | 0.02 | 312.5000 | 312.5000 | 312.5000 | 58834.45 KB | + } +} diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs index 72062fc7da..b6a4711c4d 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg } } - // RESULTS (2018 October): + // RESULTS (2018 October 31): // // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_MultiImage.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_MultiImage.cs new file mode 100644 index 0000000000..111c509cf4 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_MultiImage.cs @@ -0,0 +1,88 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Tests; +// ReSharper disable InconsistentNaming + +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg +{ + [Config(typeof(MultiImageBenchmarkBase.Config))] + public class LoadResizeSave_MultiImage : MultiImageBenchmarkBase + { + protected override IEnumerable InputImageSubfoldersOrFiles => TestImages.Jpeg.BenchmarkSuite; + + [Params(InputImageCategory.AllImages)] + public override InputImageCategory InputCategory { get; set; } + + private readonly Configuration configuration = new Configuration(new JpegConfigurationModule()); + + private byte[] destBytes; + + public override void Setup() + { + base.Setup(); + + this.configuration.MaxDegreeOfParallelism = 1; + const int MaxOutputSizeInBytes = 2 * 1024 * 1024; // ~2 MB + this.destBytes = new byte[MaxOutputSizeInBytes]; + } + + [Benchmark(Baseline = true)] + public void SystemDrawing() + { + this.ForEachStream( + sourceStream => + { + using (var destStream = new MemoryStream(this.destBytes)) + using (var source = System.Drawing.Image.FromStream(sourceStream)) + using (var destination = new Bitmap(source.Width / 4, source.Height / 4)) + { + using (var g = Graphics.FromImage(destination)) + { + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.PixelOffsetMode = PixelOffsetMode.HighQuality; + g.CompositingQuality = CompositingQuality.HighQuality; + g.DrawImage(source, 0, 0, 400, 400); + } + + destination.Save(destStream, ImageFormat.Jpeg); + } + + return null; + }); + } + + [Benchmark] + public void ImageSharp() + { + this.ForEachStream( + sourceStream => + { + using (var source = Image.Load( + this.configuration, + sourceStream, + new JpegDecoder { IgnoreMetadata = true })) + { + using (var destStream = new MemoryStream(this.destBytes)) + { + source.Mutate(c => c.Resize(source.Width / 4, source.Height / 4)); + source.SaveAsJpeg(destStream); + } + } + + return null; + }); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs b/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs index 608d3604f9..446c038596 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs @@ -3,6 +3,9 @@ // Licensed under the Apache License, Version 2.0. // +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Jobs; + using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.Codecs @@ -22,6 +25,25 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs public abstract class MultiImageBenchmarkBase { + public class Config : ManualConfig + { + public Config() + { + // Uncomment if you want to use any of the diagnoser + this.Add(new BenchmarkDotNet.Diagnosers.MemoryDiagnoser()); + } + + public class ShortClr : Benchmarks.Config + { + public ShortClr() + { + this.Add( + Job.Core.WithLaunchCount(1).WithWarmupCount(1).WithTargetCount(2) + ); + } + } + } + protected Dictionary FileNamesToBytes = new Dictionary(); protected Dictionary> FileNamesToImageSharpImages = new Dictionary>(); @@ -49,7 +71,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs /// /// Gets the file names containing these strings are substrings are not processed by the benchmark. /// - protected IEnumerable ExcludeSubstringsInFileNames => new[] { "badeof", "BadEof", "CriticalEOF" }; + protected virtual IEnumerable ExcludeSubstringsInFileNames => new[] { "badeof", "BadEof", "CriticalEOF" }; /// /// Enumerates folders containing files OR files to be processed by the benchmark. @@ -87,7 +109,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs protected abstract IEnumerable InputImageSubfoldersOrFiles { get; } [GlobalSetup] - public void ReadImages() + public virtual void Setup() { if (!Vector.IsHardwareAccelerated) { @@ -107,11 +129,13 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs continue; } + string[] excludeStrings = this.ExcludeSubstringsInFileNames.Select(s => s.ToLower()).ToArray(); + string[] allFiles = this.SearchPatterns.SelectMany( f => Directory.EnumerateFiles(path, f, SearchOption.AllDirectories) - .Where(fn => !this.ExcludeSubstringsInFileNames.Any(w => fn.ToLower().Contains(w)))).ToArray(); + .Where(fn => !excludeStrings.Any(excludeStr => fn.ToLower().Contains(excludeStr)))).ToArray(); foreach (string fn in allFiles) { diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs index 3d439c5ce7..a7f848e3a9 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs @@ -22,15 +22,19 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks { } - public static readonly TheoryData DecodeJpegData = new TheoryData() - { - //TestImages.Jpeg.Baseline.Cmyk, - //TestImages.Jpeg.Baseline.Ycck, - TestImages.Jpeg.Baseline.Calliphora, - TestImages.Jpeg.Baseline.Jpeg400, - TestImages.Jpeg.Baseline.Jpeg420Exif, - TestImages.Jpeg.Baseline.Jpeg444, - }; + public static readonly TheoryData DecodeJpegData = new TheoryData + { + // Except "Jpeg400", all images are YCbCr + + TestImages.Jpeg.Baseline.Jpeg400, + TestImages.Jpeg.Baseline.Jpeg420Exif, + TestImages.Jpeg.Baseline.Lake, // 444 + + // Using images from the "issues" set, because they are LARGE + TestImages.Jpeg.Issues.MissingFF00ProgressiveBedroom159, // 420 + TestImages.Jpeg.Issues.BadRstProgressive518, // 444 + TestImages.Jpeg.Issues.ExifGetString750Transform, // 420 + }; [Theory(Skip = ProfilingSetup.SkipProfilingTests)] [MemberData(nameof(DecodeJpegData))] @@ -38,7 +42,7 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks { this.DecodeJpegBenchmarkImpl(fileName, new JpegDecoder()); } - + private void DecodeJpegBenchmarkImpl(string fileName, IImageDecoder decoder) { // do not run this on CI even by accident @@ -47,7 +51,7 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks return; } - const int ExecutionCount = 30; + const int ExecutionCount = 10; if (!Vector.IsHardwareAccelerated) { @@ -83,29 +87,26 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks } string[] testFiles = TestImages.Bmp.All - .Concat(new[] { TestImages.Jpeg.Baseline.Calliphora, TestImages.Jpeg.Baseline.Cmyk }) - .ToArray(); + .Concat(new[] { TestImages.Jpeg.Baseline.Calliphora, TestImages.Jpeg.Baseline.Cmyk }).ToArray(); - Image[] testImages = - testFiles.Select( - tf => TestImageProvider.File(tf, pixelTypeOverride: PixelTypes.Rgba32).GetImage()) - .ToArray(); + Image[] testImages = testFiles.Select( + tf => TestImageProvider.File(tf, pixelTypeOverride: PixelTypes.Rgba32).GetImage()).ToArray(); using (var ms = new MemoryStream()) { - this.Measure(executionCount, + this.Measure( + executionCount, () => - { - foreach (Image img in testImages) { - var options = new JpegEncoder { Quality = quality, Subsample = subsample }; - img.Save(ms, options); - ms.Seek(0, SeekOrigin.Begin); - } - }, + foreach (Image img in testImages) + { + var options = new JpegEncoder { Quality = quality, Subsample = subsample }; + img.Save(ms, options); + ms.Seek(0, SeekOrigin.Begin); + } + }, // ReSharper disable once ExplicitCallerInfoArgument - $@"Encode {testFiles.Length} images" - ); + $@"Encode {testFiles.Length} images"); } foreach (Image image in testImages) @@ -113,6 +114,5 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks image.Dispose(); } } - } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 03f8754854..caffe81ab7 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -165,6 +165,19 @@ namespace SixLabors.ImageSharp.Tests } public static readonly string[] All = Baseline.All.Concat(Progressive.All).ToArray(); + + public static readonly string[] BenchmarkSuite = + { + // Except "Jpeg400", all images are YCbCr + Baseline.Jpeg400, + Baseline.Jpeg420Exif, + Baseline.Lake, // 444 + + // Using images from the "issues" set, because they are LARGE + Issues.MissingFF00ProgressiveBedroom159, // 420 + Issues.BadRstProgressive518, // 444 + Issues.ExifGetString750Transform, // 420 + }; } public static class Bmp From 5ea62adeddb2de5d8c3782b4b40ab73a6064c924 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 02:54:21 +0100 Subject: [PATCH 287/381] Drop all GetBlockDataReference() usages --- .../Decoder/JpegComponentExtensions.cs | 39 ------------- .../Jpeg/Components/Decoder/ScanDecoder.cs | 58 +++++++++++-------- .../Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs | 22 ++++--- .../Jpg/Utils/LibJpegTools.ComponentData.cs | 3 +- 4 files changed, 48 insertions(+), 74 deletions(-) delete mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentExtensions.cs diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentExtensions.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentExtensions.cs deleted file mode 100644 index d7fb52a790..0000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentExtensions.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Runtime.CompilerServices; - -using SixLabors.ImageSharp.Memory; - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder -{ - /// - /// Extension methods for - /// - internal static class JpegComponentExtensions - { - /// - /// Gets a reference to the at the given row and column index from - /// - /// The - /// The column - /// The row - /// The - [MethodImpl(InliningOptions.ShortMethod)] - public static ref Block8x8 GetBlockReference(this IJpegComponent component, int column, int row) - { - return ref component.SpectralBlocks.GetRowSpan(row)[column]; - } - - /// - /// Gets a reference to the first item in a block - /// at the given row and column index from - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static ref short GetBlockDataReference(this IJpegComponent component, int column, int row) - { - ref Block8x8 blockRef = ref component.GetBlockReference(column, row); - return ref Unsafe.As(ref blockRef); - } - } -} \ 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 39b9792ac9..ec9805309e 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs @@ -1,8 +1,10 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.IO; +using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder { @@ -179,10 +181,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder int h = component.HorizontalSamplingFactor; int v = component.VerticalSamplingFactor; + int mcuRow = mcu / mcusPerLine; + // Scan out an mcu's worth of this component; that's just determined // by the basic H and V specified for the component for (int y = 0; y < v; y++) { + int blockRow = (mcuRow * v) + y; + Span blockSpan = component.SpectralBlocks.GetRowSpan(blockRow); for (int x = 0; x < h; x++) { if (this.eof) @@ -190,15 +196,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder return; } - int mcuRow = mcu / mcusPerLine; int mcuCol = mcu % mcusPerLine; - int blockRow = (mcuRow * v) + y; int blockCol = (mcuCol * h) + x; this.DecodeBlockBaseline( component, - blockRow, - blockCol, + ref blockSpan[blockCol], ref dcHuffmanTable, ref acHuffmanTable, ref fastACRef); @@ -236,6 +239,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder int mcu = 0; for (int j = 0; j < h; j++) { + // TODO: Isn't blockRow == j actually? + int blockRow = mcu / w; + Span blockSpan = component.SpectralBlocks.GetRowSpan(blockRow); + for (int i = 0; i < w; i++) { if (this.eof) @@ -243,13 +250,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder return; } - int blockRow = mcu / w; + // TODO: Isn't blockCol == i actually? int blockCol = mcu % w; this.DecodeBlockBaseline( component, - blockRow, - blockCol, + ref blockSpan[blockCol], ref dcHuffmanTable, ref acHuffmanTable, ref fastACRef); @@ -299,6 +305,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder // by the basic H and V specified for the component for (int y = 0; y < v; y++) { + int mcuRow = mcu / mcusPerLine; + int blockRow = (mcuRow * v) + y; + Span blockSpan = component.SpectralBlocks.GetRowSpan(blockRow); + for (int x = 0; x < h; x++) { if (this.eof) @@ -306,15 +316,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder return; } - int mcuRow = mcu / mcusPerLine; int mcuCol = mcu % mcusPerLine; - int blockRow = (mcuRow * v) + y; int blockCol = (mcuCol * h) + x; this.DecodeBlockProgressiveDC( component, - blockRow, - blockCol, + ref blockSpan[blockCol], ref dcHuffmanTable); } } @@ -351,6 +358,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder int mcu = 0; for (int j = 0; j < h; j++) { + // TODO: isn't blockRow == j actually? + int blockRow = mcu / w; + Span blockSpan = component.SpectralBlocks.GetRowSpan(blockRow); + for (int i = 0; i < w; i++) { if (this.eof) @@ -358,23 +369,23 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder return; } - int blockRow = mcu / w; + // TODO: isn't blockCol == i actually? int blockCol = mcu % w; + ref Block8x8 block = ref blockSpan[blockCol]; + if (this.spectralStart == 0) { this.DecodeBlockProgressiveDC( component, - blockRow, - blockCol, + ref block, ref dcHuffmanTable); } else { this.DecodeBlockProgressiveAC( component, - blockRow, - blockCol, + ref block, ref acHuffmanTable, ref fastACRef); } @@ -391,8 +402,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder private void DecodeBlockBaseline( JpegComponent component, - int row, - int col, + ref Block8x8 block, ref HuffmanTable dcTable, ref HuffmanTable acTable, ref short fastACRef) @@ -405,7 +415,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder JpegThrowHelper.ThrowBadHuffmanCode(); } - ref short blockDataRef = ref component.GetBlockDataReference(col, row); + ref short blockDataRef = ref Unsafe.As(ref block); int diff = t != 0 ? this.ExtendReceive(t) : 0; int dc = component.DcPredictor + diff; @@ -470,8 +480,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder private void DecodeBlockProgressiveDC( JpegComponent component, - int row, - int col, + ref Block8x8 block, ref HuffmanTable dcTable) { if (this.spectralEnd != 0) @@ -481,7 +490,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder this.CheckBits(); - ref short blockDataRef = ref component.GetBlockDataReference(col, row); + ref short blockDataRef = ref Unsafe.As(ref block); if (this.successiveHigh == 0) { @@ -506,8 +515,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder private void DecodeBlockProgressiveAC( JpegComponent component, - int row, - int col, + ref Block8x8 block, ref HuffmanTable acTable, ref short fastACRef) { @@ -516,7 +524,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder JpegThrowHelper.ThrowImageFormatException("Can't merge DC and AC."); } - ref short blockDataRef = ref component.GetBlockDataReference(col, row); + ref short blockDataRef = ref Unsafe.As(ref block); if (this.successiveHigh == 0) { diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs index e161bca05b..9292d5f7de 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs @@ -46,15 +46,19 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); + // NOTE: + // The scaled result for very large image "TestImages.Jpeg.Issues.ExifGetString750Transform" + // is almost the same as the result for Jpeg420Exif, + // which proves that the execution time for the most common YCbCr 420 path scales linearly [Params( TestImages.Jpeg.Baseline.Lake, TestImages.Jpeg.Issues.BadRstProgressive518, - TestImages.Jpeg.Issues.ExifGetString750Transform, TestImages.Jpeg.Baseline.Jpeg420Exif )] public string TestImage { get; set; } + [GlobalSetup] public void ReadImages() { @@ -110,16 +114,16 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg // RESULTS (2018 November 4): // Method | TestImage | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Gen 1 | Gen 2 | Allocated | // ------------------------------- |-------------------------------------------- |-----------:|-----------:|----------:|-------:|---------:|----------:|---------:|---------:|------------:| - // 'Decode Jpeg - System.Drawing' | Jpg/baseline/Lake.jpg | 6.291 ms | 1.200 ms | 0.0678 ms | 1.00 | 0.00 | 62.5000 | - | - | 205.83 KB | - // 'Decode Jpeg - ImageSharp' | Jpg/baseline/Lake.jpg | 18.493 ms | 3.025 ms | 0.1709 ms | 2.94 | 0.03 | - | - | - | 19.97 KB | + // 'Decode Jpeg - System.Drawing' | Jpg/baseline/Lake.jpg | 6.117 ms | 0.3923 ms | 0.0222 ms | 1.00 | 0.00 | 62.5000 | - | - | 205.83 KB | + // 'Decode Jpeg - ImageSharp' | Jpg/baseline/Lake.jpg | 18.126 ms | 0.6023 ms | 0.0340 ms | 2.96 | 0.01 | - | - | - | 19.97 KB | // | | | | | | | | | | | - // 'Decode Jpeg - System.Drawing' | Jpg/baseline/jpeg420exif.jpg | 16.962 ms | 1.446 ms | 0.0817 ms | 1.00 | 0.00 | 218.7500 | - | - | 757.04 KB | - // 'Decode Jpeg - ImageSharp' | Jpg/baseline/jpeg420exif.jpg | 42.105 ms | 4.496 ms | 0.2540 ms | 2.48 | 0.02 | - | - | - | 21.94 KB | + // 'Decode Jpeg - System.Drawing' | Jpg/baseline/jpeg420exif.jpg | 17.063 ms | 2.6096 ms | 0.1474 ms | 1.00 | 0.00 | 218.7500 | - | - | 757.04 KB | + // 'Decode Jpeg - ImageSharp' | Jpg/baseline/jpeg420exif.jpg | 41.366 ms | 1.0115 ms | 0.0572 ms | 2.42 | 0.02 | - | - | - | 21.94 KB | // | | | | | | | | | | | - // 'Decode Jpeg - System.Drawing' | Jpg/issues/Issue518-Bad-RST-Progressive.jpg | 432.344 ms | 89.746 ms | 5.0708 ms | 1.00 | 0.00 | 2375.0000 | - | - | 7403.76 KB | - // 'Decode Jpeg - ImageSharp' | Jpg/issues/Issue518-Bad-RST-Progressive.jpg | 421.292 ms | 128.587 ms | 7.2654 ms | 0.97 | 0.02 | 125.0000 | 125.0000 | 125.0000 | 35186.98 KB | + // 'Decode Jpeg - System.Drawing' | Jpg/issues/Issue518-Bad-RST-Progressive.jpg | 428.282 ms | 94.9163 ms | 5.3629 ms | 1.00 | 0.00 | 2375.0000 | - | - | 7403.76 KB | + // 'Decode Jpeg - ImageSharp' | Jpg/issues/Issue518-Bad-RST-Progressive.jpg | 386.698 ms | 33.0065 ms | 1.8649 ms | 0.90 | 0.01 | 125.0000 | 125.0000 | 125.0000 | 35186.97 KB | // | | | | | | | | | | | - // 'Decode Jpeg - System.Drawing' | Jpg/issues/issue750-exif-tranform.jpg | 94.723 ms | 4.663 ms | 0.2635 ms | 1.00 | 0.00 | 1750.0000 | - | - | 5492.63 KB | - // 'Decode Jpeg - ImageSharp' | Jpg/issues/issue750-exif-tranform.jpg | 234.071 ms | 37.979 ms | 2.1459 ms | 2.47 | 0.02 | 312.5000 | 312.5000 | 312.5000 | 58834.45 KB | + // 'Decode Jpeg - System.Drawing' | Jpg/issues/issue750-exif-tranform.jpg | 95.192 ms | 3.1762 ms | 0.1795 ms | 1.00 | 0.00 | 1750.0000 | - | - | 5492.63 KB | + // 'Decode Jpeg - ImageSharp' | Jpg/issues/issue750-exif-tranform.jpg | 230.158 ms | 48.8128 ms | 2.7580 ms | 2.42 | 0.02 | 312.5000 | 312.5000 | 312.5000 | 58834.66 KB | } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs index 7acce84cea..e4fcd10c5f 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs @@ -67,9 +67,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils for (int y = 0; y < result.HeightInBlocks; y++) { + Span blockRow = c.SpectralBlocks.GetRowSpan(y); for (int x = 0; x < result.WidthInBlocks; x++) { - short[] data = c.GetBlockReference(x, y).ToArray(); + short[] data = blockRow[x].ToArray(); result.MakeBlock(data, y, x); } } From 86489b8ac634502b927d802801fa73029d5d7459 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 03:32:43 +0100 Subject: [PATCH 288/381] simplify benchmark suite --- tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs | 2 +- tests/ImageSharp.Tests/TestImages.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs index a7f848e3a9..06eb203d5f 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks // Using images from the "issues" set, because they are LARGE TestImages.Jpeg.Issues.MissingFF00ProgressiveBedroom159, // 420 - TestImages.Jpeg.Issues.BadRstProgressive518, // 444 + // TestImages.Jpeg.Issues.BadRstProgressive518, // 444 TestImages.Jpeg.Issues.ExifGetString750Transform, // 420 }; diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index caffe81ab7..35de87228f 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -175,7 +175,7 @@ namespace SixLabors.ImageSharp.Tests // Using images from the "issues" set, because they are LARGE Issues.MissingFF00ProgressiveBedroom159, // 420 - Issues.BadRstProgressive518, // 444 + // Issues.BadRstProgressive518, // 444 Issues.ExifGetString750Transform, // 420 }; } From 2ff5b9c47676cf9d456bad29fd3c5d501f240c38 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 03:35:04 +0100 Subject: [PATCH 289/381] drop old benchmark results --- .../Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs index 9292d5f7de..206a33729f 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs @@ -92,26 +92,14 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg } } - // RESULTS (2018 October 31): + // RESULTS (2018 November 4): // // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores // Frequency=2742191 Hz, Resolution=364.6719 ns, Timer=TSC // .NET Core SDK=2.1.403 // [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT - // Job-MCUBGX : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 - // Job-TZIRPF : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT - // // - // Method | Runtime | TestImage | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | - // ------------------------------- |-------- |----------------------------- |---------:|----------:|----------:|-------:|---------:|---------:|----------:| - // 'Decode Jpeg - System.Drawing' | Clr | Jpg/baseline/jpeg420exif.jpg | 17.10 ms | 4.720 ms | 0.2667 ms | 1.00 | 0.00 | 218.7500 | 757.88 KB | - // 'Decode Jpeg - ImageSharp' | Clr | Jpg/baseline/jpeg420exif.jpg | 57.77 ms | 4.626 ms | 0.2614 ms | 3.38 | 0.04 | 125.0000 | 566.01 KB | - // | | | | | | | | | | - // 'Decode Jpeg - System.Drawing' | Core | Jpg/baseline/jpeg420exif.jpg | 17.45 ms | 2.092 ms | 0.1182 ms | 1.00 | 0.00 | 218.7500 | 757.04 KB | - // 'Decode Jpeg - ImageSharp' | Core | Jpg/baseline/jpeg420exif.jpg | 48.39 ms | 14.562 ms | 0.8228 ms | 2.77 | 0.04 | 125.0000 | 529.96 KB | - - // RESULTS (2018 November 4): // Method | TestImage | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Gen 1 | Gen 2 | Allocated | // ------------------------------- |-------------------------------------------- |-----------:|-----------:|----------:|-------:|---------:|----------:|---------:|---------:|------------:| // 'Decode Jpeg - System.Drawing' | Jpg/baseline/Lake.jpg | 6.117 ms | 0.3923 ms | 0.0222 ms | 1.00 | 0.00 | 62.5000 | - | - | 205.83 KB | From 5c65cca162c08e9455bc7eb26e4b63a760bbe6a5 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 14:24:17 +0100 Subject: [PATCH 290/381] fix Block8x8FTests.Copy1x1Scale, reorganize TestImages.Jpeg.BenchmarkSuite as a static class --- ...pegMultiple.cs => DecodeJpeg_Aggregate.cs} | 21 +++++++++++++------ .../Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs | 18 +++++++++------- ...tiImage.cs => LoadResizeSave_Aggregate.cs} | 12 +++++++++-- ...ave.cs => LoadResizeSave_ImageSpecific.cs} | 9 +++++--- .../Jpg/Block8x8FTests.CopyToBufferArea.cs | 2 +- .../ProfilingBenchmarks/JpegBenchmarks.cs | 19 +++++++---------- tests/ImageSharp.Tests/TestImages.cs | 21 +++++++++---------- 7 files changed, 59 insertions(+), 43 deletions(-) rename tests/ImageSharp.Benchmarks/Codecs/Jpeg/{DecodeJpegMultiple.cs => DecodeJpeg_Aggregate.cs} (56%) rename tests/ImageSharp.Benchmarks/Codecs/Jpeg/{LoadResizeSave_MultiImage.cs => LoadResizeSave_Aggregate.cs} (84%) rename tests/ImageSharp.Benchmarks/Codecs/Jpeg/{LoadResizeSave.cs => LoadResizeSave_ImageSpecific.cs} (94%) diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs similarity index 56% rename from tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs rename to tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs index 53459e3c45..f8a7556ca5 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs @@ -10,6 +10,7 @@ using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests; using SDImage = System.Drawing.Image; +// ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { @@ -17,21 +18,29 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg /// An expensive Jpeg benchmark, running on a wide range of input images, showing aggregate results. /// [Config(typeof(MultiImageBenchmarkBase.Config))] - public class DecodeJpegMultiple : MultiImageBenchmarkBase + public class DecodeJpeg_Aggregate : MultiImageBenchmarkBase { - protected override IEnumerable InputImageSubfoldersOrFiles => TestImages.Jpeg.BenchmarkSuite; + protected override IEnumerable InputImageSubfoldersOrFiles => + new[] + { + TestImages.Jpeg.BenchmarkSuite.Jpeg400_SmallMonochrome, + TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr, + TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr, + TestImages.Jpeg.BenchmarkSuite.MissingFF00ProgressiveBedroom159_MidSize420YCbCr, + TestImages.Jpeg.BenchmarkSuite.ExifGetString750Transform_Huge420YCbCr, + }; [Params(InputImageCategory.AllImages)] public override InputImageCategory InputCategory { get; set; } - [Benchmark(Description = "DecodeJpegMultiple - ImageSharp")] - public void DecodeJpegImageSharp() + [Benchmark] + public void ImageSharp() { this.ForEachStream(ms => Image.Load(ms, new JpegDecoder())); } - [Benchmark(Baseline = true, Description = "DecodeJpegMultiple - System.Drawing")] - public void DecodeJpegSystemDrawing() + [Benchmark(Baseline = true)] + public void SystemDrawing() { this.ForEachStream(SDImage.FromStream); } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs index 206a33729f..fe112042ef 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs @@ -45,16 +45,18 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg private byte[] jpegBytes; private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); - - // NOTE: - // The scaled result for very large image "TestImages.Jpeg.Issues.ExifGetString750Transform" - // is almost the same as the result for Jpeg420Exif, - // which proves that the execution time for the most common YCbCr 420 path scales linearly + [Params( - TestImages.Jpeg.Baseline.Lake, - TestImages.Jpeg.Issues.BadRstProgressive518, + TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr, + TestImages.Jpeg.BenchmarkSuite.BadRstProgressive518_Large444YCbCr, + + // The scaled result for the large image "ExifGetString750Transform_Huge420YCbCr" + // is almost the same as the result for Jpeg420Exif, + // which proves that the execution time for the most common YCbCr 420 path scales linearly. + // + // TestImages.Jpeg.BenchmarkSuite.ExifGetString750Transform_Huge420YCbCr, - TestImages.Jpeg.Baseline.Jpeg420Exif + TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr )] public string TestImage { get; set; } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_MultiImage.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_Aggregate.cs similarity index 84% rename from tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_MultiImage.cs rename to tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_Aggregate.cs index 111c509cf4..e39cfa6ba2 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_MultiImage.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_Aggregate.cs @@ -18,9 +18,17 @@ using SixLabors.ImageSharp.Tests; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { [Config(typeof(MultiImageBenchmarkBase.Config))] - public class LoadResizeSave_MultiImage : MultiImageBenchmarkBase + public class LoadResizeSave_Aggregate : MultiImageBenchmarkBase { - protected override IEnumerable InputImageSubfoldersOrFiles => TestImages.Jpeg.BenchmarkSuite; + protected override IEnumerable InputImageSubfoldersOrFiles => + new[] + { + TestImages.Jpeg.BenchmarkSuite.Jpeg400_SmallMonochrome, + TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr, + TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr, + TestImages.Jpeg.BenchmarkSuite.MissingFF00ProgressiveBedroom159_MidSize420YCbCr, + TestImages.Jpeg.BenchmarkSuite.ExifGetString750Transform_Huge420YCbCr, + }; [Params(InputImageCategory.AllImages)] public override InputImageCategory InputCategory { get; set; } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_ImageSpecific.cs similarity index 94% rename from tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs rename to tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_ImageSpecific.cs index b6a4711c4d..1834f77eaf 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_ImageSpecific.cs @@ -11,11 +11,12 @@ using System.Drawing.Imaging; using SixLabors.ImageSharp.Processing; using SDImage = System.Drawing.Image; using SixLabors.ImageSharp.Formats.Jpeg; +// ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { [Config(typeof(Config.ShortClr))] - public class LoadResizeSave + public class LoadResizeSave_ImageSpecific { private readonly Configuration configuration = new Configuration(new JpegConfigurationModule()); @@ -26,8 +27,10 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); [Params( - TestImages.Jpeg.Baseline.Jpeg420Exif - //, TestImages.Jpeg.Baseline.Calliphora + TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr, + TestImages.Jpeg.BenchmarkSuite.BadRstProgressive518_Large444YCbCr, + + TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr )] public string TestImage { get; set; } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs index d5eaaa2949..4b1abf9094 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { Block8x8F block = CreateRandomFloatBlock(0, 100); - using (Buffer2D buffer = Configuration.Default.MemoryAllocator.Allocate2D(20, 20)) + using (Buffer2D buffer = Configuration.Default.MemoryAllocator.Allocate2D(20, 20, AllocationOptions.Clean)) { BufferArea area = buffer.GetArea(5, 10, 8, 8); block.Copy1x1Scale(area); diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs index 06eb203d5f..5bc1693bcc 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs @@ -23,18 +23,13 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks } public static readonly TheoryData DecodeJpegData = new TheoryData - { - // Except "Jpeg400", all images are YCbCr - - TestImages.Jpeg.Baseline.Jpeg400, - TestImages.Jpeg.Baseline.Jpeg420Exif, - TestImages.Jpeg.Baseline.Lake, // 444 - - // Using images from the "issues" set, because they are LARGE - TestImages.Jpeg.Issues.MissingFF00ProgressiveBedroom159, // 420 - // TestImages.Jpeg.Issues.BadRstProgressive518, // 444 - TestImages.Jpeg.Issues.ExifGetString750Transform, // 420 - }; + { + TestImages.Jpeg.BenchmarkSuite.Jpeg400_SmallMonochrome, + TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr, + TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr, + TestImages.Jpeg.BenchmarkSuite.MissingFF00ProgressiveBedroom159_MidSize420YCbCr, + TestImages.Jpeg.BenchmarkSuite.ExifGetString750Transform_Huge420YCbCr, + }; [Theory(Skip = ProfilingSetup.SkipProfilingTests)] [MemberData(nameof(DecodeJpegData))] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 35de87228f..8da458e520 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -166,18 +166,17 @@ namespace SixLabors.ImageSharp.Tests public static readonly string[] All = Baseline.All.Concat(Progressive.All).ToArray(); - public static readonly string[] BenchmarkSuite = + public static class BenchmarkSuite { - // Except "Jpeg400", all images are YCbCr - Baseline.Jpeg400, - Baseline.Jpeg420Exif, - Baseline.Lake, // 444 - - // Using images from the "issues" set, because they are LARGE - Issues.MissingFF00ProgressiveBedroom159, // 420 - // Issues.BadRstProgressive518, // 444 - Issues.ExifGetString750Transform, // 420 - }; + public const string Jpeg400_SmallMonochrome = Baseline.Jpeg400; + public const string Jpeg420Exif_MidSizeYCbCr = Baseline.Jpeg420Exif; + public const string Lake_Small444YCbCr = Baseline.Lake; + + // A few large images from the "issues" set are actually very useful for benchmarking: + public const string MissingFF00ProgressiveBedroom159_MidSize420YCbCr = Issues.MissingFF00ProgressiveBedroom159; + public const string BadRstProgressive518_Large444YCbCr = Issues.BadRstProgressive518; + public const string ExifGetString750Transform_Huge420YCbCr = Issues.ExifGetString750Transform; + } } public static class Bmp From fd1ce9842c8d8f4bc1b8a7b2e291454e9684116d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 14:49:03 +0100 Subject: [PATCH 291/381] oops --- tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs index 267c70219e..f9a68d4e7c 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. // Uncomment to enable local profiling benchmarks. DO NOT PUSH TO MAIN! -#define PROFILING +// #define PROFILING namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks { From 300ee6a555455624ab9d025be6be9a6b14040262 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 16:11:45 +0100 Subject: [PATCH 292/381] move ResizeProfilingBenchmarks, use the ***ProfilingBenchmarks naming convention everywhere --- tests/ImageSharp.Sandbox46/Program.cs | 4 ++-- .../{JpegBenchmarks.cs => JpegProfilingBenchmarks.cs} | 4 ++-- ...hmarks.cs => LoadResizeSaveProfilingBenchmarks.cs} | 4 ++-- .../ResizeProfilingBenchmarks.cs | 11 ++--------- 4 files changed, 8 insertions(+), 15 deletions(-) rename tests/ImageSharp.Tests/ProfilingBenchmarks/{JpegBenchmarks.cs => JpegProfilingBenchmarks.cs} (96%) rename tests/ImageSharp.Tests/ProfilingBenchmarks/{LoadResizeSaveBenchmarks.cs => LoadResizeSaveProfilingBenchmarks.cs} (89%) rename tests/ImageSharp.Tests/{Processing/Processors/Transforms => ProfilingBenchmarks}/ResizeProfilingBenchmarks.cs (82%) diff --git a/tests/ImageSharp.Sandbox46/Program.cs b/tests/ImageSharp.Sandbox46/Program.cs index c0bb25a1b9..02d4f80c55 100644 --- a/tests/ImageSharp.Sandbox46/Program.cs +++ b/tests/ImageSharp.Sandbox46/Program.cs @@ -63,8 +63,8 @@ namespace SixLabors.ImageSharp.Sandbox46 private static void RunDecodeJpegProfilingTests() { Console.WriteLine("RunDecodeJpegProfilingTests..."); - var benchmarks = new JpegBenchmarks(new ConsoleOutput()); - foreach (object[] data in JpegBenchmarks.DecodeJpegData) + var benchmarks = new JpegProfilingBenchmarks(new ConsoleOutput()); + foreach (object[] data in JpegProfilingBenchmarks.DecodeJpegData) { string fileName = (string)data[0]; benchmarks.DecodeJpeg(fileName); diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs similarity index 96% rename from tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs rename to tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs index 5bc1693bcc..609aa43b74 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs @@ -15,9 +15,9 @@ using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks { - public class JpegBenchmarks : MeasureFixture + public class JpegProfilingBenchmarks : MeasureFixture { - public JpegBenchmarks(ITestOutputHelper output) + public JpegProfilingBenchmarks(ITestOutputHelper output) : base(output) { } diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveProfilingBenchmarks.cs similarity index 89% rename from tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveBenchmarks.cs rename to tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveProfilingBenchmarks.cs index 3060722768..95fe4e48f1 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveProfilingBenchmarks.cs @@ -10,9 +10,9 @@ using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks { - public class LoadResizeSaveBenchmarks : MeasureFixture + public class LoadResizeSaveProfilingBenchmarks : MeasureFixture { - public LoadResizeSaveBenchmarks(ITestOutputHelper output) + public LoadResizeSaveProfilingBenchmarks(ITestOutputHelper output) : base(output) { } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/ResizeProfilingBenchmarks.cs similarity index 82% rename from tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs rename to tests/ImageSharp.Tests/ProfilingBenchmarks/ResizeProfilingBenchmarks.cs index e24458d384..8b93559381 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/ResizeProfilingBenchmarks.cs @@ -7,17 +7,10 @@ using SixLabors.ImageSharp.Processing; using Xunit; using Xunit.Abstractions; -namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms +namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks { public class ResizeProfilingBenchmarks : MeasureFixture { - public const string SkipText = -#if false - null; -#else - "Benchmark, enable manually!"; -#endif - private readonly Configuration configuration = Configuration.CreateDefaultInstance(); public ResizeProfilingBenchmarks(ITestOutputHelper output) @@ -28,7 +21,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms public int ExecutionCount { get; set; } = 50; - [Theory(Skip = SkipText)] + [Theory(Skip = ProfilingSetup.SkipProfilingTests)] [InlineData(100, 100)] [InlineData(2000, 2000)] public void ResizeBicubic(int width, int height) From f45ed5dee0611426555677328e8e747179396c69 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 16:59:15 +0100 Subject: [PATCH 293/381] simplify ResizeKernel.Convolve(...) --- .../Processing/Processors/Transforms/ResizeKernel.cs | 4 ++-- .../Processors/Transforms/ResizeProcessor.cs | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs index cc3c204534..be4b7a741d 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs @@ -73,11 +73,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The source row position. /// The weighted sum [MethodImpl(InliningOptions.ShortMethod)] - public Vector4 Convolve(Span rowSpan, int sourceX) + public Vector4 Convolve(Span rowSpan) { ref float horizontalValues = ref this.GetStartReference(); int left = this.Left; - ref Vector4 vecPtr = ref Unsafe.Add(ref MemoryMarshal.GetReference(rowSpan), left + sourceX); + ref Vector4 vecPtr = ref Unsafe.Add(ref MemoryMarshal.GetReference(rowSpan), left); // Destination color components Vector4 result = Vector4.Zero; diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 4d4ed06ce1..d0d225d9bf 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -254,8 +254,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { for (int y = rows.Min; y < rows.Max; y++) { - Span sourceRow = source.GetPixelRowSpan(y); - Span tempRowSpan = tempRowBuffer.Span; + Span sourceRow = source.GetPixelRowSpan(y).Slice(sourceX); + Span tempRowSpan = tempRowBuffer.Span.Slice(sourceX); PixelOperations.Instance.ToVector4(configuration, sourceRow, tempRowSpan); Vector4Utils.Premultiply(tempRowSpan); @@ -271,7 +271,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { ResizeKernel window = this.horizontalKernelMap.Kernels[x - startX]; Unsafe.Add(ref firstPassBaseRef, x * sourceHeight) = - window.Convolve(tempRowSpan, sourceX); + window.Convolve(tempRowSpan); } } }); @@ -295,10 +295,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int x = 0; x < width; x++) { - Span firstPassColumn = firstPassPixelsTransposed.GetRowSpan(x); + Span firstPassColumn = firstPassPixelsTransposed.GetRowSpan(x).Slice(sourceY); // Destination color components - Unsafe.Add(ref tempRowBase, x) = window.Convolve(firstPassColumn, sourceY); + Unsafe.Add(ref tempRowBase, x) = window.Convolve(firstPassColumn); } Vector4Utils.UnPremultiply(tempRowSpan); From 32e0497dca2f1921d5903ef82f69c6d564728237 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 19:59:06 +0100 Subject: [PATCH 294/381] minor refactor on ResizeKernel --- .../Processors/Transforms/KernelMap.cs | 3 ++- .../Processors/Transforms/ResizeKernel.cs | 22 ++++--------------- .../Processors/Transforms/KernelMapTests.cs | 14 +++++++----- 3 files changed, 14 insertions(+), 25 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs index 277be53fff..f7a3a6f6de 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs @@ -3,6 +3,7 @@ using System; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory; using SixLabors.Memory; @@ -89,7 +90,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms ResizeKernel ws = result.CreateKernel(i, left, right); result.Kernels[i] = ws; - ref float weightsBaseRef = ref ws.GetStartReference(); + ref float weightsBaseRef = ref MemoryMarshal.GetReference(ws.GetValues()); for (int j = left; j <= right; j++) { diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs index be4b7a741d..707f1467b0 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs @@ -2,13 +2,11 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory; -using SixLabors.Memory; namespace SixLabors.ImageSharp.Processing.Processors.Transforms { @@ -18,12 +16,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms internal struct ResizeKernel { /// - /// The local left index position + /// The left index for the destination row /// public int Left; /// - /// The length of the weights window + /// The length of the kernel /// public int Length; @@ -48,34 +46,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.Length = length; } - /// - /// Gets a reference to the first item of the window. - /// - /// The reference to the first item of the window - [MethodImpl(InliningOptions.ShortMethod)] - public ref float GetStartReference() - { - Span span = this.buffer.Span; - return ref span[0]; - } - /// /// Gets the span representing the portion of the that this window covers /// /// The [MethodImpl(InliningOptions.ShortMethod)] - public Span GetSpan() => this.buffer.Span; + public Span GetValues() => this.buffer.Span; /// /// 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(InliningOptions.ShortMethod)] public Vector4 Convolve(Span rowSpan) { - ref float horizontalValues = ref this.GetStartReference(); + ref float horizontalValues = ref MemoryMarshal.GetReference(this.GetValues()); int left = this.Left; ref Vector4 vecPtr = ref Unsafe.Add(ref MemoryMarshal.GetReference(rowSpan), left); diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index 1b4b3cf6a3..a7d93ad1d8 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -21,10 +21,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms this.Output = output; } - [Theory(Skip = "TODO: Add asserionts")] + [Theory] [InlineData(500, 200, nameof(KnownResamplers.Bicubic))] [InlineData(50, 40, nameof(KnownResamplers.Bicubic))] [InlineData(40, 30, nameof(KnownResamplers.Bicubic))] + [InlineData(15, 10, nameof(KnownResamplers.Bicubic))] [InlineData(500, 200, nameof(KnownResamplers.Lanczos8))] [InlineData(100, 80, nameof(KnownResamplers.Lanczos8))] [InlineData(100, 10, nameof(KnownResamplers.Lanczos8))] @@ -37,14 +38,15 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms var bld = new StringBuilder(); - foreach (ResizeKernel window in kernelMap.Kernels) + foreach (ResizeKernel kernel in kernelMap.Kernels) { - Span span = window.GetSpan(); - for (int i = 0; i < window.Length; i++) + bld.Append($"({kernel.Left:D3}) || "); + Span span = kernel.GetValues(); + for (int i = 0; i < kernel.Length; i++) { float value = span[i]; - bld.Append($"{value,7:F4}"); - bld.Append("| "); + bld.Append($"{value,7:F5}"); + bld.Append(" | "); } bld.AppendLine(); From 99a641625c4b3ef46c4a6b67ad694c6a2c7c5206 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 20:44:22 +0100 Subject: [PATCH 295/381] drop unused parameter --- src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs | 2 -- tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs index ec9805309e..5d232b5713 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs @@ -384,7 +384,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder else { this.DecodeBlockProgressiveAC( - component, ref block, ref acHuffmanTable, ref fastACRef); @@ -514,7 +513,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } private void DecodeBlockProgressiveAC( - JpegComponent component, ref Block8x8 block, ref HuffmanTable acTable, ref short fastACRef) diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs index 5bc1693bcc..e06d2da916 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs @@ -28,6 +28,7 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr, TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr, TestImages.Jpeg.BenchmarkSuite.MissingFF00ProgressiveBedroom159_MidSize420YCbCr, + TestImages.Jpeg.BenchmarkSuite.BadRstProgressive518_Large444YCbCr, TestImages.Jpeg.BenchmarkSuite.ExifGetString750Transform_Huge420YCbCr, }; @@ -46,7 +47,7 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks return; } - const int ExecutionCount = 10; + const int ExecutionCount = 20; if (!Vector.IsHardwareAccelerated) { From f425190dc7f7bb0c686d251cb31f04d3b9785b84 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 21:59:18 +0100 Subject: [PATCH 296/381] Cover KernelMap with tests --- .../Processors/Transforms/KernelMap.cs | 18 ++-- .../Processors/Transforms/ResizeProcessor.cs | 8 +- .../KernelMapTests.ReferenceKernelMap.cs | 99 +++++++++++++++++++ .../Processors/Transforms/KernelMapTests.cs | 42 +++++--- 4 files changed, 145 insertions(+), 22 deletions(-) create mode 100644 tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs index f7a3a6f6de..b0fd0e2cde 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs @@ -17,6 +17,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { private readonly Buffer2D data; + private readonly ResizeKernel[] kernels; + /// /// Initializes a new instance of the class. /// @@ -25,15 +27,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The radius of the kernel public KernelMap(MemoryAllocator memoryAllocator, int destinationSize, float kernelRadius) { + this.DestinationSize = destinationSize; int width = (int)Math.Ceiling(kernelRadius * 2); this.data = memoryAllocator.Allocate2D(width, destinationSize, AllocationOptions.Clean); - this.Kernels = new ResizeKernel[destinationSize]; + this.kernels = new ResizeKernel[destinationSize]; } - /// - /// Gets the calculated values. - /// - public ResizeKernel[] Kernels { get; } + public int DestinationSize { get; } /// /// Disposes instance releasing it's backing buffer. @@ -43,6 +43,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.data.Dispose(); } + /// + /// Returns a for an index value between 0 and destinationSize - 1. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public ref ResizeKernel GetKernel(int destIdx) => ref this.kernels[destIdx]; + /// /// Computes the weights to apply at each pixel when resizing. /// @@ -88,7 +94,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms float sum = 0; ResizeKernel ws = result.CreateKernel(i, left, right); - result.Kernels[i] = ws; + result.kernels[i] = ws; ref float weightsBaseRef = ref MemoryMarshal.GetReference(ws.GetValues()); diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index d0d225d9bf..7c9d39fc55 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -269,9 +269,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int x = minX; x < maxX; x++) { - ResizeKernel window = this.horizontalKernelMap.Kernels[x - startX]; + ResizeKernel kernel = this.horizontalKernelMap.GetKernel(x - startX); Unsafe.Add(ref firstPassBaseRef, x * sourceHeight) = - window.Convolve(tempRowSpan); + kernel.Convolve(tempRowSpan); } } }); @@ -289,7 +289,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int y = rows.Min; y < rows.Max; y++) { // Ensure offsets are normalized for cropping and padding. - ResizeKernel window = this.verticalKernelMap.Kernels[y - startY]; + ResizeKernel kernel = this.verticalKernelMap.GetKernel(y - startY); ref Vector4 tempRowBase = ref MemoryMarshal.GetReference(tempRowSpan); @@ -298,7 +298,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Span firstPassColumn = firstPassPixelsTransposed.GetRowSpan(x).Slice(sourceY); // Destination color components - Unsafe.Add(ref tempRowBase, x) = window.Convolve(firstPassColumn); + Unsafe.Add(ref tempRowBase, x) = kernel.Convolve(firstPassColumn); } Vector4Utils.UnPremultiply(tempRowSpan); diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs new file mode 100644 index 0000000000..932ea54948 --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; + +using SixLabors.ImageSharp.Processing.Processors.Transforms; + +namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms +{ + public partial class KernelMapTests + { + /// + /// Simplified reference implementation for functionality. + /// + public class ReferenceKernelMap + { + private readonly ReferenceKernel[] kernels; + + public ReferenceKernelMap(ReferenceKernel[] kernels) + { + this.kernels = kernels; + } + + public int DestinationSize => this.kernels.Length; + + public ReferenceKernel GetKernel(int destinationIndex) => this.kernels[destinationIndex]; + + public static ReferenceKernelMap Calculate(IResampler sampler, int destinationSize, int sourceSize) + { + float ratio = (float)sourceSize / destinationSize; + float scale = ratio; + + if (scale < 1F) + { + scale = 1F; + } + + float radius = MathF.Ceiling(scale * sampler.Radius); + + var result = new List(); + + 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; + + float[] values = new float[right - left + 1]; + + for (int j = left; j <= right; j++) + { + float weight = sampler.GetValue((j - center) / scale); + sum += weight; + + values[j - left] = weight; + } + + result.Add(new ReferenceKernel(left, values)); + + if (sum > 0) + { + for (int w = 0; w < values.Length; w++) + { + values[w] /= sum; + } + } + } + + return new ReferenceKernelMap(result.ToArray()); + } + } + + public struct ReferenceKernel + { + public ReferenceKernel(int left, float[] values) + { + this.Left = left; + this.Values = values; + } + + public int Left { get; } + + public float[] Values { get; } + + public int Length => this.Values.Length; + } + } +} \ 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 index a7d93ad1d8..9f4d53b964 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -12,7 +12,7 @@ using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { - public class KernelMapTests + public partial class KernelMapTests { private ITestOutputHelper Output { get; } @@ -30,34 +30,52 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms [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) + public void KernelMapContentIsCorrect(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 referenceMap = ReferenceKernelMap.Calculate(resampler, destSize, srcSize); + +#if DEBUG + string text = PrintKernelMap(kernelMap); + this.Output.WriteLine(text); +#endif + + for (int i = 0; i < kernelMap.DestinationSize; i++) + { + ResizeKernel kernel = kernelMap.GetKernel(i); + + ReferenceKernel referenceKernel = referenceMap.GetKernel(i); + + Assert.Equal(referenceKernel.Length, kernel.Length); + Assert.Equal(referenceKernel.Left, kernel.Left); + Assert.True(kernel.GetValues().SequenceEqual(referenceKernel.Values)); + } + } + + private static string PrintKernelMap(KernelMap kernelMap) + { var bld = new StringBuilder(); - foreach (ResizeKernel kernel in kernelMap.Kernels) + for (int i = 0; i < kernelMap.DestinationSize; i++) { + ResizeKernel kernel = kernelMap.GetKernel(i); bld.Append($"({kernel.Left:D3}) || "); Span span = kernel.GetValues(); - for (int i = 0; i < kernel.Length; i++) + + for (int j = 0; j < kernel.Length; j++) { - float value = span[i]; - bld.Append($"{value,7:F5}"); + float value = span[j]; + bld.Append($"{value,8:F5}"); 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()); + return bld.ToString(); } } } \ No newline at end of file From 41972e90c8e1f69b14d920adc368a8fd8c6f3db2 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 22:17:46 +0100 Subject: [PATCH 297/381] refactor ResizeKernel creation --- .../Processors/Transforms/KernelMap.cs | 13 ++++--- .../Processors/Transforms/ResizeKernel.cs | 34 ++++++++----------- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs index b0fd0e2cde..278fd93d82 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The to use for allocations. /// The size of the destination window /// The radius of the kernel - public KernelMap(MemoryAllocator memoryAllocator, int destinationSize, float kernelRadius) + private KernelMap(MemoryAllocator memoryAllocator, int destinationSize, float kernelRadius) { this.DestinationSize = destinationSize; int width = (int)Math.Ceiling(kernelRadius * 2); @@ -125,13 +125,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// 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) + private ResizeKernel CreateKernel(int destIdx, int left, int rightIdx) { - return new ResizeKernel(destIdx, leftIdx, this.data, rightIdx - leftIdx + 1); + int flatStartIndex = destIdx * this.data.Width; + int length = rightIdx - left + 1; + Memory bufferSlice = this.data.Memory.Slice(flatStartIndex, length); + return new ResizeKernel(left, bufferSlice); } } } \ 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 707f1467b0..1ce9c9c91e 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs @@ -16,42 +16,36 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms internal struct ResizeKernel { /// - /// The left index for the destination row + /// Initializes a new instance of the struct. /// - public int Left; + [MethodImpl(InliningOptions.ShortMethod)] + internal ResizeKernel(int left, Memory bufferSlice) + { + this.Left = left; + this.BufferSlice = bufferSlice; + } /// - /// The length of the kernel + /// Gets the left index for the destination row /// - public int Length; + public int Left { get; } /// - /// The buffer containing the weights values. + /// Gets the slice of the buffer containing the weights values. /// - private readonly Memory buffer; + public Memory BufferSlice { get; } /// - /// Initializes a new instance of the struct. + /// Gets the the length of the kernel /// - /// The destination index in the buffer - /// The local left index - /// The span - /// The length of the window - [MethodImpl(InliningOptions.ShortMethod)] - internal ResizeKernel(int index, int left, Buffer2D buffer, int length) - { - int flatStartIndex = index * buffer.Width; - this.Left = left; - this.buffer = buffer.MemorySource.Memory.Slice(flatStartIndex, length); - this.Length = length; - } + public int Length => this.BufferSlice.Length; /// /// Gets the span representing the portion of the that this window covers /// /// The [MethodImpl(InliningOptions.ShortMethod)] - public Span GetValues() => this.buffer.Span; + public Span GetValues() => this.BufferSlice.Span; /// /// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this instance. From 9a122870b00ddb6d381580d155c50b06ee58d88a Mon Sep 17 00:00:00 2001 From: Anton Firsov Date: Mon, 5 Nov 2018 01:33:06 +0100 Subject: [PATCH 298/381] Fix EnumHelper.IsDefined --- src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs index c6a5b7d232..100649c0fd 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs @@ -567,8 +567,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif [MethodImpl(InliningOptions.ShortMethod)] public static bool IsDefined(int value) { - return Array.BinarySearch(Values, 0, Values.Length, value) > 0; + return Array.BinarySearch(Values, value) >= 0; } } } -} \ No newline at end of file +} From e059620f19f9391e40806d6961bc00813a56494d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 5 Nov 2018 01:34:03 +0100 Subject: [PATCH 299/381] KernelMap refactor WIP --- .../ImageSharp.Drawing.csproj | 3 +- src/ImageSharp/ImageSharp.csproj | 3 +- .../Processors/Transforms/KernelMap.cs | 34 ++++++++++----- .../ImageSharp.Benchmarks.csproj | 3 +- .../ImageSharp.Tests/ImageSharp.Tests.csproj | 3 +- .../Processors/Transforms/KernelMapTests.cs | 42 ++++++++++++++----- 6 files changed, 64 insertions(+), 24 deletions(-) diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index 1cb3f444f0..6341e1771c 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -5,7 +5,8 @@ $(packageversion) 0.0.1 SixLabors and contributors - netstandard1.3;netstandard2.0 + + netcoreapp2.1 7.3 true true diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 29d29d50d8..e2f55e3c6a 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -5,7 +5,8 @@ $(packageversion) 0.0.1 Six Labors and contributors - netstandard1.3;netstandard2.0;netcoreapp2.1;net472 + + netcoreapp2.1 true true SixLabors.ImageSharp diff --git a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs index 278fd93d82..3f984fef0d 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs @@ -19,16 +19,23 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private readonly ResizeKernel[] kernels; - /// - /// Initializes a new instance of the class. - /// - /// The to use for allocations. - /// The size of the destination window - /// The radius of the kernel - private KernelMap(MemoryAllocator memoryAllocator, int destinationSize, float kernelRadius) + private int period; + + private int radius; + + private int periodicRegionMin; + + private int periodicRegionMax; + + private KernelMap(MemoryAllocator memoryAllocator, int destinationSize, int radius, int period) { this.DestinationSize = destinationSize; - int width = (int)Math.Ceiling(kernelRadius * 2); + this.period = period; + this.radius = radius; + this.periodicRegionMin = period + radius; + this.periodicRegionMax = destinationSize - radius; + + int width = radius * 2; this.data = memoryAllocator.Allocate2D(width, destinationSize, AllocationOptions.Clean); this.kernels = new ResizeKernel[destinationSize]; } @@ -71,8 +78,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms scale = 1F; } - float radius = MathF.Ceiling(scale * sampler.Radius); - var result = new KernelMap(memoryAllocator, destinationSize, radius); + int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize; + + int radius = (int)MathF.Ceiling(scale * sampler.Radius); + var result = new KernelMap(memoryAllocator, destinationSize, radius, period); for (int i = 0; i < destinationSize; i++) { @@ -122,6 +131,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return result; } + private int ReduceIndex(int destIndex) + { + return destIndex; + } + /// /// Slices a weights value at the given positions. /// diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index a705c9bacb..04a4541b21 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -1,6 +1,7 @@  - netcoreapp2.1;net461 + + netcoreapp2.1 Exe True SixLabors.ImageSharp.Benchmarks diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 86c1a7a259..75ac7450c8 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -1,6 +1,7 @@  - net462;net472;netcoreapp2.1 + + netcoreapp2.1 True latest full diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index 9f4d53b964..7abc1c3122 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -20,17 +20,39 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { this.Output = output; } - + + /// + /// resamplerName, srcSize, destSize + /// + public static readonly TheoryData KernelMapData = new TheoryData + { + { nameof(KnownResamplers.Bicubic), 15, 10 }, + { nameof(KnownResamplers.Bicubic), 10, 15 }, + { nameof(KnownResamplers.Bicubic), 20, 20 }, + { nameof(KnownResamplers.Bicubic), 50, 40 }, + { nameof(KnownResamplers.Bicubic), 40, 50 }, + { nameof(KnownResamplers.Bicubic), 500, 200 }, + { nameof(KnownResamplers.Bicubic), 200, 500 }, + + { nameof(KnownResamplers.Lanczos3), 16, 12 }, + { nameof(KnownResamplers.Lanczos3), 12, 16 }, + { nameof(KnownResamplers.Lanczos3), 12, 9 }, + { nameof(KnownResamplers.Lanczos3), 9, 12 }, + { nameof(KnownResamplers.Lanczos3), 6, 8 }, + { nameof(KnownResamplers.Lanczos3), 8, 6 }, + + // TODO: What's wrong here: + // { nameof(KnownResamplers.Lanczos3), 20, 12 }, + + {nameof(KnownResamplers.Lanczos8), 500, 200 }, + {nameof(KnownResamplers.Lanczos8), 100, 10 }, + {nameof(KnownResamplers.Lanczos8), 100, 80 }, + {nameof(KnownResamplers.Lanczos8), 10, 100 }, + }; + [Theory] - [InlineData(500, 200, nameof(KnownResamplers.Bicubic))] - [InlineData(50, 40, nameof(KnownResamplers.Bicubic))] - [InlineData(40, 30, nameof(KnownResamplers.Bicubic))] - [InlineData(15, 10, 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 KernelMapContentIsCorrect(int srcSize, int destSize, string resamplerName) + [MemberData(nameof(KernelMapData))] + public void KernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) { var resampler = (IResampler)typeof(KnownResamplers).GetProperty(resamplerName).GetValue(null); From e79f26bc7ec9cfca5bedb2309d7b7486c9da79ea Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 5 Nov 2018 10:55:22 +0000 Subject: [PATCH 300/381] Add base becnhmark --- .../InterpolatedTransformProcessorBase.cs | 5 +-- .../ImageSharp.Benchmarks/Samplers/Rotate.cs | 39 +++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 tests/ImageSharp.Benchmarks/Samplers/Rotate.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/InterpolatedTransformProcessorBase.cs b/src/ImageSharp/Processing/Processors/Transforms/InterpolatedTransformProcessorBase.cs index c1abb4a5e1..4737a4102c 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/InterpolatedTransformProcessorBase.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/InterpolatedTransformProcessorBase.cs @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int i = 0; i < length; i++) { ref float wRef = ref Unsafe.Add(ref weightsRef, i); - wRef = wRef / sum; + wRef /= sum; } } } @@ -90,8 +90,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { for (int x = 0, i = sourceMin; i <= sourceMax; i++, x++) { - float weight = sampler.GetValue(i - point); - Unsafe.Add(ref weightsRef, x) = weight; + Unsafe.Add(ref weightsRef, x) = sampler.GetValue(i - point); } } diff --git a/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs b/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs new file mode 100644 index 0000000000..c1456f9d77 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs @@ -0,0 +1,39 @@ +using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Benchmarks.Samplers +{ + [Config(typeof(Config.ShortClr))] + public class Rotate + { + [Benchmark] + public Size DoRotate() + { + using (var image = new Image(Configuration.Default, 400, 400, Rgba32.BlanchedAlmond)) + { + image.Mutate(x => x.Rotate(37.5F)); + + return image.Size(); + } + } + } +} + +// Nov 4 2018 +//BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17763 +//Intel Core i7-6600U CPU 2.60GHz(Skylake), 1 CPU, 4 logical and 2 physical cores +//.NET Core SDK = 2.1.403 + +// [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT +// Job-KKDIMW : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 +// Job-IUZRFA : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + +//LaunchCount=1 TargetCount=3 WarmupCount=3 + +// #### BEFORE ####: +// Method | Runtime | Mean | Error | StdDev | Allocated | +//--------- |-------- |---------:|----------:|----------:|----------:| +// DoRotate | Clr | 85.19 ms | 13.379 ms | 0.7560 ms | 6 KB | +// DoRotate | Core | 53.51 ms | 9.512 ms | 0.5375 ms | 4.29 KB | \ No newline at end of file From 0fe5525febe603d5509deed1894ad5829ba8e73e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 5 Nov 2018 10:57:55 +0000 Subject: [PATCH 301/381] Remove unused declaration. --- .../Processors/Quantization/PaletteQuantizer{TPixel}.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs index e2f302f1ee..ac143a767b 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs @@ -61,8 +61,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } TPixel[] paletteRef = this.palette; - TPixel1[] castPalette = Unsafe.As(ref paletteRef); - return new PaletteFrameQuantizer(this, Unsafe.As(ref paletteRef)); } From 8de843200fb96e78aba7f68fd34eda094233af08 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 5 Nov 2018 13:49:14 +0000 Subject: [PATCH 302/381] Mask the PaletteQuantizer.CreateFrameQuantizer() methods. --- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 2 +- .../Quantization/PaletteQuantizer{TPixel}.cs | 36 ++++++--- .../Quantization/OctreeQuantizerTests.cs | 58 ++++++++++++++ .../Quantization/PaletteQuantizerTests.cs | 79 +++++++++++++++++++ .../Quantization/WuQuantizerTests.cs | 58 ++++++++++++++ 5 files changed, 223 insertions(+), 10 deletions(-) create mode 100644 tests/ImageSharp.Tests/Processing/Processors/Quantization/OctreeQuantizerTests.cs create mode 100644 tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs create mode 100644 tests/ImageSharp.Tests/Processing/Processors/Quantization/WuQuantizerTests.cs diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index de68cd46ee..17ee616072 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.Formats.Gif } else { - using (QuantizedFrame paletteQuantized = palleteQuantizer.CreateFrameQuantizer(image.GetConfiguration()).QuantizeFrame(frame)) + using (QuantizedFrame paletteQuantized = palleteQuantizer.CreateFrameQuantizer(image.GetConfiguration()).QuantizeFrame(frame)) { this.WriteImageData(paletteQuantized, stream); } diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs index ac143a767b..a350adfc0c 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs @@ -15,8 +15,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public class PaletteQuantizer : IQuantizer where TPixel : struct, IPixel { - private readonly TPixel[] palette; - /// /// Initializes a new instance of the class. /// @@ -44,36 +42,56 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public PaletteQuantizer(TPixel[] palette, IErrorDiffuser diffuser) { Guard.MustBeBetweenOrEqualTo(palette.Length, QuantizerConstants.MinColors, QuantizerConstants.MaxColors, nameof(palette)); - this.palette = palette; + this.Palette = palette; this.Diffuser = diffuser; } /// public IErrorDiffuser Diffuser { get; } + /// + /// Gets the palette. + /// + public TPixel[] Palette { get; } + + /// + /// Creates the generic frame quantizer. + /// + /// The to configure internal operations. + /// The . + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration) + => ((IQuantizer)this).CreateFrameQuantizer(configuration); + + /// + /// Creates the generic frame quantizer. + /// + /// The to configure internal operations. + /// The maximum number of colors to hold in the color palette. + /// The . + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) + => ((IQuantizer)this).CreateFrameQuantizer(configuration, maxColors); + /// - public IFrameQuantizer CreateFrameQuantizer(Configuration configuration) - where TPixel1 : struct, IPixel + IFrameQuantizer IQuantizer.CreateFrameQuantizer(Configuration configuration) { if (!typeof(TPixel).Equals(typeof(TPixel1))) { throw new InvalidOperationException("Generic method type must be the same as class type."); } - TPixel[] paletteRef = this.palette; + TPixel[] paletteRef = this.Palette; return new PaletteFrameQuantizer(this, Unsafe.As(ref paletteRef)); } /// - public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) - where TPixel1 : struct, IPixel + IFrameQuantizer IQuantizer.CreateFrameQuantizer(Configuration configuration, int maxColors) { if (!typeof(TPixel).Equals(typeof(TPixel1))) { throw new InvalidOperationException("Generic method type must be the same as class type."); } - TPixel[] paletteRef = this.palette; + TPixel[] paletteRef = this.Palette; TPixel1[] castPalette = Unsafe.As(ref paletteRef); maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); diff --git a/tests/ImageSharp.Tests/Processing/Processors/Quantization/OctreeQuantizerTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Quantization/OctreeQuantizerTests.cs new file mode 100644 index 0000000000..b3900325db --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Processors/Quantization/OctreeQuantizerTests.cs @@ -0,0 +1,58 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Processors.Quantization; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Processing.Processors.Quantization +{ + public class OctreeQuantizerTests + { + [Fact] + public void OctreeQuantizerConstructor() + { + var quantizer = new OctreeQuantizer(128); + + Assert.Equal(128, quantizer.MaxColors); + Assert.Equal(KnownDiffusers.FloydSteinberg, quantizer.Diffuser); + + quantizer = new OctreeQuantizer(false); + Assert.Equal(QuantizerConstants.MaxColors, quantizer.MaxColors); + Assert.Null(quantizer.Diffuser); + + quantizer = new OctreeQuantizer(KnownDiffusers.Atkinson); + Assert.Equal(QuantizerConstants.MaxColors, quantizer.MaxColors); + Assert.Equal(KnownDiffusers.Atkinson, quantizer.Diffuser); + + quantizer = new OctreeQuantizer(KnownDiffusers.Atkinson, 128); + Assert.Equal(128, quantizer.MaxColors); + Assert.Equal(KnownDiffusers.Atkinson, quantizer.Diffuser); + } + + [Fact] + public void OctreeQuantizerCanCreateFrameQuantizer() + { + var quantizer = new OctreeQuantizer(); + IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + + Assert.NotNull(frameQuantizer); + Assert.True(frameQuantizer.Dither); + Assert.Equal(KnownDiffusers.FloydSteinberg, frameQuantizer.Diffuser); + + quantizer = new OctreeQuantizer(false); + frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + + Assert.NotNull(frameQuantizer); + Assert.False(frameQuantizer.Dither); + Assert.Null(frameQuantizer.Diffuser); + + quantizer = new OctreeQuantizer(KnownDiffusers.Atkinson); + frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + Assert.NotNull(frameQuantizer); + Assert.True(frameQuantizer.Dither); + Assert.Equal(KnownDiffusers.Atkinson, frameQuantizer.Diffuser); + } + } +} diff --git a/tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs new file mode 100644 index 0000000000..a4e6edd53e --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs @@ -0,0 +1,79 @@ +// 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.Quantization; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Processing.Processors.Quantization +{ + public class PaletteQuantizerTests + { + private static readonly Rgba32[] Rgb = new Rgba32[] { Rgba32.Red, Rgba32.Green, Rgba32.Blue }; + + [Fact] + public void PaletteQuantizerConstructor() + { + var quantizer = new PaletteQuantizer(Rgb); + + Assert.Equal(Rgb, quantizer.Palette); + Assert.Equal(KnownDiffusers.FloydSteinberg, quantizer.Diffuser); + + quantizer = new PaletteQuantizer(Rgb, false); + Assert.Equal(Rgb, quantizer.Palette); + Assert.Null(quantizer.Diffuser); + + quantizer = new PaletteQuantizer(Rgb, KnownDiffusers.Atkinson); + Assert.Equal(Rgb, quantizer.Palette); + Assert.Equal(KnownDiffusers.Atkinson, quantizer.Diffuser); + } + + [Fact] + public void PaletteQuantizerCanCreateFrameQuantizer() + { + var quantizer = new PaletteQuantizer(Rgb); + IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + + Assert.NotNull(frameQuantizer); + Assert.True(frameQuantizer.Dither); + Assert.Equal(KnownDiffusers.FloydSteinberg, frameQuantizer.Diffuser); + + quantizer = new PaletteQuantizer(Rgb, false); + frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + + Assert.NotNull(frameQuantizer); + Assert.False(frameQuantizer.Dither); + Assert.Null(frameQuantizer.Diffuser); + + quantizer = new PaletteQuantizer(Rgb, KnownDiffusers.Atkinson); + frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + Assert.NotNull(frameQuantizer); + Assert.True(frameQuantizer.Dither); + Assert.Equal(KnownDiffusers.Atkinson, frameQuantizer.Diffuser); + } + + [Fact] + public void PaletteQuantizerThrowsOnInvalidGenericMethodCall() + { + var quantizer = new PaletteQuantizer(Rgb); + + Assert.Throws(() => ((IQuantizer)quantizer).CreateFrameQuantizer(Configuration.Default)); + } + + [Fact] + public void KnownQuantizersWebSafeTests() + { + IQuantizer quantizer = KnownQuantizers.WebSafe; + Assert.Equal(KnownDiffusers.FloydSteinberg, quantizer.Diffuser); + } + + [Fact] + public void KnownQuantizersWernerTests() + { + IQuantizer quantizer = KnownQuantizers.Werner; + Assert.Equal(KnownDiffusers.FloydSteinberg, quantizer.Diffuser); + } + } +} diff --git a/tests/ImageSharp.Tests/Processing/Processors/Quantization/WuQuantizerTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Quantization/WuQuantizerTests.cs new file mode 100644 index 0000000000..625043c7f1 --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Processors/Quantization/WuQuantizerTests.cs @@ -0,0 +1,58 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Processors.Quantization; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Processing.Processors.Quantization +{ + public class WuQuantizerTests + { + [Fact] + public void WuQuantizerConstructor() + { + var quantizer = new WuQuantizer(128); + + Assert.Equal(128, quantizer.MaxColors); + Assert.Equal(KnownDiffusers.FloydSteinberg, quantizer.Diffuser); + + quantizer = new WuQuantizer(false); + Assert.Equal(QuantizerConstants.MaxColors, quantizer.MaxColors); + Assert.Null(quantizer.Diffuser); + + quantizer = new WuQuantizer(KnownDiffusers.Atkinson); + Assert.Equal(QuantizerConstants.MaxColors, quantizer.MaxColors); + Assert.Equal(KnownDiffusers.Atkinson, quantizer.Diffuser); + + quantizer = new WuQuantizer(KnownDiffusers.Atkinson, 128); + Assert.Equal(128, quantizer.MaxColors); + Assert.Equal(KnownDiffusers.Atkinson, quantizer.Diffuser); + } + + [Fact] + public void WuQuantizerCanCreateFrameQuantizer() + { + var quantizer = new WuQuantizer(); + IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + + Assert.NotNull(frameQuantizer); + Assert.True(frameQuantizer.Dither); + Assert.Equal(KnownDiffusers.FloydSteinberg, frameQuantizer.Diffuser); + + quantizer = new WuQuantizer(false); + frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + + Assert.NotNull(frameQuantizer); + Assert.False(frameQuantizer.Dither); + Assert.Null(frameQuantizer.Diffuser); + + quantizer = new WuQuantizer(KnownDiffusers.Atkinson); + frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + Assert.NotNull(frameQuantizer); + Assert.True(frameQuantizer.Dither); + Assert.Equal(KnownDiffusers.Atkinson, frameQuantizer.Diffuser); + } + } +} From 7e519e75019207d42d0aebe1add4d6675be666e1 Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Mon, 5 Nov 2018 13:27:08 -0600 Subject: [PATCH 303/381] ImageSharp-762_Aot-compiling: moved AoT methods to AotCompiler static class --- src/ImageSharp/Advanced/AotCompiler.cs | 103 ++++++++++++++++++ src/ImageSharp/Formats/Gif/ImageExtensions.cs | 42 ------- 2 files changed, 103 insertions(+), 42 deletions(-) create mode 100644 src/ImageSharp/Advanced/AotCompiler.cs diff --git a/src/ImageSharp/Advanced/AotCompiler.cs b/src/ImageSharp/Advanced/AotCompiler.cs new file mode 100644 index 0000000000..1c7f12ef7b --- /dev/null +++ b/src/ImageSharp/Advanced/AotCompiler.cs @@ -0,0 +1,103 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Dithering; +using SixLabors.ImageSharp.Processing.Processors.Quantization; + +namespace SixLabors.ImageSharp.Advanced +{ + /// + /// Unlike traditional Mono/.NET, code on the iPhone is statically compiled ahead of time instead of being + /// compiled on demand by a JIT compiler. This means there are a few limitations with respect to generics, + /// these are caused because not every possible generic instantiation can be determined up front at compile time. + /// The Aot Compiler is designed to overcome the limitations of this compiler. + /// + public static class AotCompiler + { + /// + /// Seeds the compiler using the given pixel format. + /// + /// The pixel format. + public static void Seed() + where TPixel : struct, IPixel + { + // This is we actually call all the individual methods you need to seed. + AotCompileOctreeQuantizer(); + AotCompileWuQuantizer(); + AotCompileDithering(); + + // TODO: Do the discovery work to figure out what works and what doesn't. + } + + /// + /// Seeds the compiler using the given pixel formats. + /// + /// The first pixel format. + /// The second pixel format. + public static void Seed() + where TPixel : struct, IPixel + where TPixel2 : struct, IPixel + { + Seed(); + Seed(); + } + + /// + /// Seeds the compiler using the given pixel formats. + /// + /// The first pixel format. + /// The second pixel format. + /// The third pixel format. + public static void Seed() + where TPixel : struct, IPixel + where TPixel2 : struct, IPixel + where TPixel3 : struct, IPixel + { + Seed(); + Seed(); + } + + /// + /// This method doesn't actually do anything but serves an important purpose... + /// If you are running ImageSharp on iOS and try to call SaveAsGif, it will throw an excepion: + /// "Attempting to JIT compile method... OctreeFrameQuantizer.ConstructPalette... while running in aot-only mode." + /// The reason this happens is the SaveAsGif method makes haevy use of generics, which are too confusing for the AoT + /// compiler used on Xamarin.iOS. It spins up the JIT compiler to try and figure it out, but that is an illegal op on + /// iOS so it bombs out. + /// If you are getting the above error, you need to call this method, which will pre-seed the AoT compiler with the + /// necessary methods to complete the SaveAsGif call. That's it, otherwise you should NEVER need this method!!! + /// + /// The pixel format. + private static void AotCompileOctreeQuantizer() + where TPixel : struct, IPixel + { + var test = new OctreeFrameQuantizer(new OctreeQuantizer(false)); + test.AotGetPalette(); + } + + /// + /// This method pre-seeds the WuQuantizer in the AoT compiler for iOS. + /// + /// The pixel format. + private static void AotCompileWuQuantizer() + where TPixel : struct, IPixel + { + var test = new WuFrameQuantizer(new WuQuantizer(false)); + test.QuantizeFrame(new ImageFrame(Configuration.Default, 1, 1)); + test.AotGetPalette(); + } + + /// + /// This method pre-seeds the default dithering engine (FloydSteinbergDiffuser) in the AoT compiler for iOS. + /// + /// The pixel format. + private static void AotCompileDithering() + where TPixel : struct, IPixel + { + var test = new FloydSteinbergDiffuser(); + TPixel pixel = default; + test.Dither(new ImageFrame(Configuration.Default, 1, 1), pixel, pixel, 0, 0, 0, 0, 0, 0); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs index f1c2ae5fb5..3939299e90 100644 --- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs @@ -38,47 +38,5 @@ namespace SixLabors.ImageSharp public static void SaveAsGif(this Image source, Stream stream, GifEncoder encoder) where TPixel : struct, IPixel => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(GifFormat.Instance)); - - /// - /// This method doesn't actually do anything but serves an important purpose... - /// If you are running ImageSharp on iOS and try to call SaveAsGif, it will throw an excepion: - /// "Attempting to JIT compile method... OctreeFrameQuantizer.ConstructPalette... while running in aot-only mode." - /// The reason this happens is the SaveAsGif method makes haevy use of generics, which are too confusing for the AoT - /// compiler used on Xamarin.iOS. It spins up the JIT compiler to try and figure it out, but that is an illegal op on - /// iOS so it bombs out. - /// If you are getting the above error, you need to call this method, which will pre-seed the AoT compiler with the - /// necessary methods to complete the SaveAsGif call. That's it, otherwise you should NEVER need this method!!! - /// - /// The pixel format. - public static void AotCompileOctreeQuantizer() - where TPixel : struct, IPixel - { - var test = new OctreeFrameQuantizer(new OctreeQuantizer(false)); - test.AotGetPalette(); - } - - /// - /// This method pre-seeds the WuQuantizer in the AoT compiler for iOS. - /// - /// The pixel format. - public static void AotCompileWuQuantizer() - where TPixel : struct, IPixel - { - var test = new WuFrameQuantizer(new WuQuantizer(false)); - test.QuantizeFrame(new ImageFrame(Configuration.Default, 1, 1)); - test.AotGetPalette(); - } - - /// - /// This method pre-seeds the default dithering engine (FloydSteinbergDiffuser) in the AoT compiler for iOS. - /// - /// The pixel format. - public static void AotCompileDithering() - where TPixel : struct, IPixel - { - var test = new FloydSteinbergDiffuser(); - TPixel pixel = default; - test.Dither(new ImageFrame(Configuration.Default, 1, 1), pixel, pixel, 0, 0, 0, 0, 0, 0); - } } } From 788319b26d99f2ef57fc7b7f25a8466f887390a4 Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Mon, 5 Nov 2018 13:28:17 -0600 Subject: [PATCH 304/381] ImageSharp-762_Aot-compiling: namespace cleanup --- src/ImageSharp/Formats/Gif/ImageExtensions.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs index 3939299e90..8ddd4247e1 100644 --- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs @@ -5,9 +5,6 @@ using System.IO; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Primitives; -using SixLabors.ImageSharp.Processing.Processors.Dithering; -using SixLabors.ImageSharp.Processing.Processors.Quantization; namespace SixLabors.ImageSharp { From 9e006c734eca190e2d1b5701986c5699aa43bf39 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 11:12:25 +0100 Subject: [PATCH 305/381] fix typos in comments --- .../Processors/Drawing/FillRegionProcessor.cs | 6 +-- .../Processors/Text/DrawTextProcessor.cs | 4 +- .../Processing/SolidBrush{TPixel}.cs | 2 +- .../Advanced/AdvancedImageExtensions.cs | 6 +-- src/ImageSharp/Common/Helpers/ImageMaths.cs | 2 +- .../Helpers/SimdUtils.BasicIntrinsics256.cs | 2 +- src/ImageSharp/Common/Helpers/SimdUtils.cs | 4 +- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 2 +- .../Formats/Bmp/IBmpDecoderOptions.cs | 2 +- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 2 +- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 4 +- src/ImageSharp/Formats/Gif/LzwEncoder.cs | 4 +- src/ImageSharp/Formats/IImageFormat.cs | 4 +- .../Formats/Jpeg/Components/Block8x8.cs | 6 +-- .../Formats/Jpeg/Components/Block8x8F.cs | 4 +- .../JpegColorConverter.FromYCbCrSimd.cs | 4 +- .../JpegColorConverter.FromYCbCrSimdAvx2.cs | 2 +- .../ColorConverters/JpegColorConverter.cs | 2 +- .../Jpeg/Components/Decoder/HuffmanTable.cs | 2 +- .../Jpeg/Components/Decoder/IRawJpegData.cs | 2 +- .../Jpeg/Components/Decoder/JFifMarker.cs | 2 +- .../Decoder/JpegBlockPostProcessor.cs | 2 +- .../Decoder/JpegComponentPostProcessor.cs | 2 +- .../Jpeg/Components/Decoder/ScanDecoder.cs | 4 +- .../Components/Encoder/RgbToYCbCrTables.cs | 2 +- .../Jpeg/Components/GenericBlock8x8.cs | 2 +- .../Formats/Jpeg/JpegDecoderCore.cs | 4 +- .../Formats/Png/Chunks/PhysicalChunkData.cs | 2 +- .../Formats/Png/IPngDecoderOptions.cs | 2 +- src/ImageSharp/IImageInfo.cs | 2 +- src/ImageSharp/Image.WrapMemory.cs | 24 +++++------ src/ImageSharp/ImageExtensions.cs | 4 +- src/ImageSharp/Image{TPixel}.cs | 2 +- .../Profiles/ICC/Enums/IccProfileClass.cs | 10 ++--- .../Profiles/ICC/Enums/IccProfileFlag.cs | 4 +- .../Profiles/ICC/Enums/IccProfileTag.cs | 42 +++++++++---------- .../Profiles/ICC/Enums/IccRenderingIntent.cs | 10 ++--- .../Profiles/ICC/Enums/IccTypeSignature.cs | 28 ++++++------- .../PixelFormats/ColorBuilder{TPixel}.cs | 2 +- .../PixelFormats/PixelOperations{TPixel}.cs | 2 +- .../PixelFormats/Utils/PixelConverter.cs | 2 +- .../Utils/Vector4Converters.RgbaCompatible.cs | 2 +- 42 files changed, 111 insertions(+), 111 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs index 514249a2d4..1dc63efa27 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs @@ -82,11 +82,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing // we need to offset the pixel grid to account for when we outline a path. // basically if the line is [1,2] => [3,2] then when outlining at 1 we end up with a region of [0.5,1.5],[1.5, 1.5],[3.5,2.5],[2.5,2.5] // and this can cause missed fills when not using antialiasing.so we offset the pixel grid by 0.5 in the x & y direction thus causing the# - // region to alline with the pixel grid. + // region to align with the pixel grid. float offset = 0.5f; if (this.Options.Antialias) { - offset = 0f; // we are antialising skip offsetting as real antalising should take care of offset. + offset = 0f; // we are antialiasing skip offsetting as real antialiasing should take care of offset. subpixelCount = this.Options.AntialiasSubpixelDepth; if (subpixelCount < 4) { @@ -121,7 +121,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing int pointsFound = region.Scan(subPixel + offset, buffer, configuration); if (pointsFound == 0) { - // nothing on this line skip + // nothing on this line, skip continue; } diff --git a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs index f9a1d87393..487c880644 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text /// The font we want to render with /// The brush to source pixel colors from. /// The pen to outline text with. - /// The location on the image to start drawign the text from. + /// The location on the image to start drawing the text from. public DrawTextProcessor(TextGraphicsOptions options, string text, Font font, IBrush brush, IPen pen, PointF location) { Guard.NotNull(text, nameof(text)); @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text { base.BeforeImageApply(source, sourceRectangle); - // do everythign at the image level as we are deligating the processing down to other processors + // do everything at the image level as we are delegating the processing down to other processors var style = new RendererOptions(this.Font, this.Options.DpiX, this.Options.DpiY, this.Location) { ApplyKerning = this.Options.ApplyKerning, diff --git a/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs index 6a80287706..20a6833c40 100644 --- a/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs @@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.Processing { Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x); - // constrain the spans to eachother + // constrain the spans to each other if (destinationRow.Length > scanline.Length) { destinationRow = destinationRow.Slice(0, scanline.Length); diff --git a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs index 328d575969..63ccea4e66 100644 --- a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs +++ b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs @@ -160,7 +160,7 @@ namespace SixLabors.ImageSharp.Advanced /// /// The type of the pixel. /// The source. - /// The span retuned from Pixel source + /// The span returned from Pixel source private static Span GetSpan(IPixelSource source) where TPixel : struct, IPixel => source.PixelBuffer.GetSpan(); @@ -172,7 +172,7 @@ namespace SixLabors.ImageSharp.Advanced /// The source. /// The row. /// - /// The span retuned from Pixel source + /// The span returned from Pixel source /// private static Span GetSpan(IPixelSource source, int row) where TPixel : struct, IPixel @@ -185,7 +185,7 @@ namespace SixLabors.ImageSharp.Advanced /// The source. /// The row. /// - /// The span retuned from Pixel source + /// The span returned from Pixel source /// private static Span GetSpan(Buffer2D source, int row) where TPixel : struct, IPixel diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 402aa79b5f..f07ccb03b4 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp /// /// Scales a value from an 8 bit to it's 16 bit equivalent. /// - /// The 8 bit compoonent value. + /// The 8 bit component value. /// The [MethodImpl(InliningOptions.ShortMethod)] public static ushort UpscaleFrom8BitTo16Bit(byte component) => (ushort)(component * 257); diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs index 0f1ce2ab6a..85c9f00748 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp var bVec = new Vector(256.0f / 255.0f); var magicFloat = new Vector(32768.0f); - var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f + var magicInt = new Vector(1191182336); // reinterpreted value of 32768.0f var mask = new Vector(255); ref Octet.OfByte sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index a989cc8752..867e7b9de1 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -169,7 +169,7 @@ namespace SixLabors.ImageSharp DebugGuard.IsTrue( ImageMaths.ModuloP2(dest.Length, shouldBeDivisibleBy) == 0, nameof(source), - $"length should be divisable by {shouldBeDivisibleBy}!"); + $"length should be divisible by {shouldBeDivisibleBy}!"); } [Conditional("DEBUG")] @@ -179,7 +179,7 @@ namespace SixLabors.ImageSharp DebugGuard.IsTrue( ImageMaths.ModuloP2(dest.Length, shouldBeDivisibleBy) == 0, nameof(source), - $"length should be divisable by {shouldBeDivisibleBy}!"); + $"length should be divisible by {shouldBeDivisibleBy}!"); } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index cea90cb45e..eb519f4214 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -207,7 +207,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// /// Looks up color values and builds the image from de-compressed RLE8 data. - /// Compresssed RLE8 stream is uncompressed by + /// Compressed RLE8 stream is uncompressed by /// /// The pixel format. /// The to assign the palette to. diff --git a/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs b/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs index c44ca73f2e..219d37ca62 100644 --- a/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs +++ b/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs @@ -8,6 +8,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// internal interface IBmpDecoderOptions { - // added this for consistancy so we can add stuff as required, no options currently availible + // added this for consistency so we can add stuff as required, no options currently available } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index db512a0781..b8a270b3f5 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.Formats.Gif private GifGraphicControlExtension graphicsControlExtension; /// - /// The image desciptor. + /// The image descriptor. /// private GifImageDescriptor imageDescriptor; diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 17ee616072..a922f30117 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Formats.Gif internal sealed class GifEncoderCore { /// - /// Used for allocating memory during procesing operations. + /// Used for allocating memory during processing operations. /// private readonly MemoryAllocator memoryAllocator; @@ -421,7 +421,7 @@ namespace SixLabors.ImageSharp.Formats.Gif private void WriteColorTable(QuantizedFrame image, Stream stream) where TPixel : struct, IPixel { - // The maximium number of colors for the bit depth + // The maximum number of colors for the bit depth int colorTableLength = ImageMaths.GetColorCountForBitDepth(this.bitDepth) * 3; int pixelCount = image.Palette.Length; diff --git a/src/ImageSharp/Formats/Gif/LzwEncoder.cs b/src/ImageSharp/Formats/Gif/LzwEncoder.cs index e390dfd54c..34c353ec97 100644 --- a/src/ImageSharp/Formats/Gif/LzwEncoder.cs +++ b/src/ImageSharp/Formats/Gif/LzwEncoder.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Formats.Gif }; /// - /// The maximium number of bits/code. + /// The maximum number of bits/code. /// private const int MaxBits = 12; @@ -210,7 +210,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// flush the packet to disk. /// /// The character to add. - /// The reference to the storage for packat accumulators + /// The reference to the storage for packet accumulators /// The stream to write to. [MethodImpl(MethodImplOptions.AggressiveInlining)] private void AddCharacter(byte c, ref byte accumulatorsRef, Stream stream) diff --git a/src/ImageSharp/Formats/IImageFormat.cs b/src/ImageSharp/Formats/IImageFormat.cs index 94191c1493..3cd289df76 100644 --- a/src/ImageSharp/Formats/IImageFormat.cs +++ b/src/ImageSharp/Formats/IImageFormat.cs @@ -16,12 +16,12 @@ namespace SixLabors.ImageSharp.Formats string Name { get; } /// - /// Gets the default mimetype that the image foramt uses + /// Gets the default mimetype that the image format uses /// string DefaultMimeType { get; } /// - /// Gets all the mimetypes that have been used by this image foramt. + /// Gets all the mimetypes that have been used by this image format. /// IEnumerable MimeTypes { get; } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs index 5601a94366..60fec25d29 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs @@ -10,7 +10,7 @@ using System.Text; namespace SixLabors.ImageSharp.Formats.Jpeg.Components { /// - /// Represents a Jpeg block with coefficiens. + /// Represents a Jpeg block with coefficients. /// // ReSharper disable once InconsistentNaming internal unsafe struct Block8x8 : IEquatable @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components } /// - /// Gets or sets a value in a row+coulumn of the 8x8 block + /// Gets or sets a value in a row+column of the 8x8 block /// /// The x position index in the row /// The column index @@ -283,7 +283,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components } /// - /// Calculate the total sum of absoulute differences of elements in 'a' and 'b'. + /// Calculate the total sum of absolute differences of elements in 'a' and 'b'. /// public static long TotalDifference(ref Block8x8 a, ref Block8x8 b) { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs index 137a8029d8..2be5addc2f 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs @@ -395,7 +395,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components } /// - /// Scales the 16x16 region represented by the 4 source blocks to the 8x8 DST block. + /// Scales the 16x16 region represented by the 4 source blocks to the 8x8 DST block. /// /// The destination block. /// The source block. @@ -571,7 +571,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components // sign(dividend) = max(min(dividend, 1), -1) var sign = Vector4.Clamp(dividend, NegativeOne, Vector4.One); - // AlmostRound(dividend/divisor) = dividend/divisior + 0.5*sign(dividend) + // AlmostRound(dividend/divisor) = dividend/divisor + 0.5*sign(dividend) return (dividend / divisor) + (sign * Offset); } 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 1dc72aaf5b..23aa1acbe6 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs @@ -32,11 +32,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters } /// - /// SIMD convert using buffers of sizes divisable by 8. + /// SIMD convert using buffers of sizes divisible by 8. /// internal static void ConvertCore(in ComponentValues values, Span result) { - DebugGuard.IsTrue(result.Length % 8 == 0, nameof(result), "result.Length should be divisable by 8!"); + DebugGuard.IsTrue(result.Length % 8 == 0, nameof(result), "result.Length should be divisible by 8!"); ref Vector4Pair yBase = ref Unsafe.As(ref MemoryMarshal.GetReference(values.Component0)); 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 46644258b1..f0a70a6f38 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters } /// - /// SIMD convert using buffers of sizes divisable by 8. + /// SIMD convert using buffers of sizes divisible by 8. /// internal static void ConvertCore(in ComponentValues values, Span result) { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs index 456636dc39..a44ebf89d1 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters internal abstract partial class JpegColorConverter { /// - /// The avalilable converters + /// The available converters /// private static readonly JpegColorConverter[] Converters = { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs index 24d570bf1c..9e134746bc 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs @@ -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 needit later. + // Compute largest code + 1 for this size. preshifted as we need it later. Unsafe.Add(ref maxcodeRef, k) = code << (16 - k); code <<= 1; } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs index dace78b337..1454bb5b12 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder Size ImageSizeInPixels { get; } /// - /// Gets the number of coponents. + /// Gets the number of components. /// int ComponentCount { get; } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs index f153ce062a..4bff492486 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// The minor version /// The units for the density values /// The horizontal pixel density - /// The veritcal pixel density + /// The vertical pixel density private JFifMarker(byte majorVersion, byte minorVersion, byte densityUnits, short xDensity, short yDensity) { Guard.MustBeGreaterThan(xDensity, 0, nameof(xDensity)); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs index 0108e30815..da4b2847b8 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// - Dequantize /// - Applying IDCT /// - Level shift by +128, clip to [0, 255] - /// - Copy the resultin color values into 'destArea' scaling up the block by amount defined in + /// - Copy the resulting color values into 'destArea' scaling up the block by amount defined in /// /// The source block. /// The destination buffer area. diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs index 57a53549f5..94ec600dd5 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder private int currentComponentRowInBlocks; /// - /// The size of the area in corrsponding to one 8x8 Jpeg block + /// The size of the area in corresponding to one 8x8 Jpeg block /// private readonly Size blockAreaSize; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs index 5d232b5713..48abca2a4e 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs @@ -755,7 +755,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder [MethodImpl(InliningOptions.ColdPath)] private void FillBuffer() { - // Attempt to load at least the minimum nbumber of required bits into the buffer. + // Attempt to load at least the minimum number of required bits into the buffer. // We fail to do so only if we hit a marker or reach the end of the input stream. do { @@ -912,7 +912,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } // If it's NOT a restart, then just bail, so we get corrupt data rather than no data. - // Reset the stream to before any bad markers to ensure we can read sucessive segments. + // Reset the stream to before any bad markers to ensure we can read successive segments. if (this.badMarker) { this.stream.Position = this.markerPosition; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs index a0cc9ee8e5..cb0810985e 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder /// /// Initializes the YCbCr tables /// - /// The intialized + /// The initialized public static RgbToYCbCrTables Create() { RgbToYCbCrTables tables = default; diff --git a/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs b/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs index 2e20da266b..c795ccc8b5 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// FOR TESTING ONLY! - /// Gets or sets a value in a row+coulumn of the 8x8 block + /// Gets or sets a value in a row+column of the 8x8 block /// /// The x position index in the row /// The column index diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index ef73aab38f..67f665576b 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -51,12 +51,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg private readonly byte[] markerBuffer = new byte[2]; /// - /// The DC HUffman tables + /// The DC Huffman tables /// private HuffmanTables dcHuffmanTables; /// - /// The AC HUffman tables + /// The AC Huffman tables /// private HuffmanTables acHuffmanTables; diff --git a/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs b/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs index 07fc688d50..6ab0dd6576 100644 --- a/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs +++ b/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Chunks /// /// Constructs the PngPhysicalChunkData from the provided metadata. - /// If the resolution units are not in meters, they are automatically convereted. + /// If the resolution units are not in meters, they are automatically converted. /// /// The metadata. /// The constructed PngPhysicalChunkData instance. diff --git a/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs b/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs index bd0b932056..5b650ac2a0 100644 --- a/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs +++ b/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs @@ -6,7 +6,7 @@ using System.Text; namespace SixLabors.ImageSharp.Formats.Png { /// - /// The optioas for decoding png images + /// The options for decoding png images /// internal interface IPngDecoderOptions { diff --git a/src/ImageSharp/IImageInfo.cs b/src/ImageSharp/IImageInfo.cs index 25d5ec7cab..6e64aa679a 100644 --- a/src/ImageSharp/IImageInfo.cs +++ b/src/ImageSharp/IImageInfo.cs @@ -7,7 +7,7 @@ using SixLabors.ImageSharp.MetaData; namespace SixLabors.ImageSharp { /// - /// Encapsulates properties that descibe basic image information including dimensions, pixel type information + /// Encapsulates properties that describe basic image information including dimensions, pixel type information /// and additional metadata /// public interface IImageInfo diff --git a/src/ImageSharp/Image.WrapMemory.cs b/src/ImageSharp/Image.WrapMemory.cs index e8d9ab7547..c2935bed93 100644 --- a/src/ImageSharp/Image.WrapMemory.cs +++ b/src/ImageSharp/Image.WrapMemory.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp public static partial class Image { /// - /// Wraps an existing contigous memory area of 'width'x'height' pixels, + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an ImageSharp instance. /// /// The pixel type @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp } /// - /// Wraps an existing contigous memory area of 'width'x'height' pixels, + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an ImageSharp instance. /// /// The pixel type @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp } /// - /// Wraps an existing contigous memory area of 'width'x'height' pixels, + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an ImageSharp instance. /// The memory is being observed, the caller remains responsible for managing it's lifecycle. /// @@ -79,15 +79,15 @@ namespace SixLabors.ImageSharp } /// - /// Wraps an existing contigous memory area of 'width'x'height' pixels, + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an ImageSharp instance. - /// The ownership of the is being transfered to the new instance, + /// The ownership of the is being transferred to the new instance, /// meaning that the caller is not allowed to dispose . /// It will be disposed together with the result image. /// /// The pixel type /// The - /// The that is being transfered to the image + /// The that is being transferred to the image /// The width of the memory image /// The height of the memory image /// The @@ -105,15 +105,15 @@ namespace SixLabors.ImageSharp } /// - /// Wraps an existing contigous memory area of 'width'x'height' pixels, + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an ImageSharp instance. - /// The ownership of the is being transfered to the new instance, + /// The ownership of the is being transferred to the new instance, /// meaning that the caller is not allowed to dispose . /// It will be disposed together with the result image. /// /// The pixel type /// The - /// The that is being transfered to the image + /// The that is being transferred to the image /// The width of the memory image /// The height of the memory image /// An instance @@ -128,14 +128,14 @@ namespace SixLabors.ImageSharp } /// - /// Wraps an existing contigous memory area of 'width'x'height' pixels, + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an ImageSharp instance. - /// The ownership of the is being transfered to the new instance, + /// The ownership of the is being transferred to the new instance, /// meaning that the caller is not allowed to dispose . /// It will be disposed together with the result image. /// /// The pixel type - /// The that is being transfered to the image + /// The that is being transferred to the image /// The width of the memory image /// The height of the memory image /// An instance diff --git a/src/ImageSharp/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs index e579bec1a6..cbf93275c8 100644 --- a/src/ImageSharp/ImageExtensions.cs +++ b/src/ImageSharp/ImageExtensions.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp if (format is null) { var sb = new StringBuilder(); - sb.AppendLine($"Can't find a format that is associated with the file extention '{ext}'. Registered formats with there extensions include:"); + sb.AppendLine($"Can't find a format that is associated with the file extension '{ext}'. Registered formats with there extensions include:"); foreach (IImageFormat fmt in source.GetConfiguration().ImageFormats) { sb.AppendLine($" - {fmt.Name} : {string.Join(", ", fmt.FileExtensions)}"); @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp if (encoder is null) { var sb = new StringBuilder(); - sb.AppendLine($"Can't find encoder for file extention '{ext}' using image format '{format.Name}'. Registered encoders include:"); + sb.AppendLine($"Can't find encoder for file extension '{ext}' using image format '{format.Name}'. Registered encoders include:"); foreach (KeyValuePair enc in source.GetConfiguration().ImageFormatsManager.ImageEncoders) { sb.AppendLine($" - {enc.Key} : {enc.Value.GetType().Name}"); diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index 9d4c1ef0b3..178194b21e 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -186,7 +186,7 @@ namespace SixLabors.ImageSharp public Image Clone() => this.Clone(this.configuration); /// - /// Clones the current image with the given configueation. + /// Clones the current image with the given configuration. /// /// The configuration providing initialization code which allows extending the library. /// Returns a new with all the same pixel data as the original. diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileClass.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileClass.cs index 71c27ca611..8f0427db27 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileClass.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileClass.cs @@ -39,15 +39,15 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// /// This profile provides the relevant information to perform a transformation - /// between colour encodings and the PCS. This type of profile is based on - /// modelling rather than device measurement or characterization data. + /// between color encodings and the PCS. This type of profile is based on + /// modeling rather than device measurement or characterization data. /// ColorSpace profiles may be embedded in images. /// ColorSpace = 0x73706163, // spac /// /// This profile represents abstract transforms and does not represent any - /// device model. Colour transformations using Abstract profiles are performed + /// device model. Color transformations using Abstract profiles are performed /// from PCS to PCS. Abstract profiles cannot be embedded in images. /// Abstract = 0x61627374, // abst @@ -55,8 +55,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// /// NamedColor profiles can be thought of as sibling profiles to device profiles. /// For a given device there would be one or more device profiles to handle - /// process colour conversions and one or more named colour profiles to handle - /// named colours. + /// process color conversions and one or more named color profiles to handle + /// named colors. /// NamedColor = 0x6E6D636C, // nmcl } diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileFlag.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileFlag.cs index 3758be34b7..1e9ec18e89 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileFlag.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileFlag.cs @@ -29,12 +29,12 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc NotEmbedded = 0, /// - /// Profile cannot be used independently of the embedded colour data + /// Profile cannot be used independently of the embedded color data /// NotIndependent = 1 << 1, /// - /// Profile can be used independently of the embedded colour data + /// Profile can be used independently of the embedded color data /// Independent = 0, } diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileTag.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileTag.cs index 82b2969003..61d34dca10 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileTag.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileTag.cs @@ -19,18 +19,18 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc Unknown, /// - /// A2B0 - This tag defines a colour transform from Device, Colour Encoding or PCS, to PCS, or a colour transform + /// A2B0 - This tag defines a color transform from Device, Color Encoding or PCS, to PCS, or a color transform /// from Device 1 to Device 2, using lookup table tag element structures /// AToB0 = 0x41324230, /// - /// A2B2 - This tag describes the colour transform from Device or Colour Encoding to PCS using lookup table tag element structures + /// A2B2 - This tag describes the color transform from Device or Color Encoding to PCS using lookup table tag element structures /// AToB1 = 0x41324231, /// - /// A2B2 - This tag describes the colour transform from Device or Colour Encoding to PCS using lookup table tag element structures + /// A2B2 - This tag describes the color transform from Device or Color Encoding to PCS using lookup table tag element structures /// AToB2 = 0x41324232, @@ -46,40 +46,40 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc BlueTrc = 0x62545243, /// - /// B2A0 - This tag defines a colour transform from PCS to Device or Colour Encoding using the lookup table tag element structures + /// B2A0 - This tag defines a color transform from PCS to Device or Color Encoding using the lookup table tag element structures /// BToA0 = 0x42324130, /// - /// B2A1 - This tag defines a colour transform from PCS to Device or Colour Encoding using the lookup table tag element structures. + /// B2A1 - This tag defines a color transform from PCS to Device or Color Encoding using the lookup table tag element structures. /// BToA1 = 0x42324131, /// - /// B2A2 - This tag defines a colour transform from PCS to Device or Colour Encoding using the lookup table tag element structures. + /// B2A2 - This tag defines a color transform from PCS to Device or Color Encoding using the lookup table tag element structures. /// BToA2 = 0x42324132, /// - /// B2D0 - This tag defines a colour transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and + /// B2D0 - This tag defines a color transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and /// provides a means to override the BToA0 tag. /// BToD0 = 0x42324430, /// - /// B2D1 - This tag defines a colour transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and + /// B2D1 - This tag defines a color transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and /// provides a means to override the BToA1 tag. /// BToD1 = 0x42324431, /// - /// B2D2 - This tag defines a colour transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and + /// B2D2 - This tag defines a color transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and /// provides a means to override the BToA2 tag. /// BToD2 = 0x42324432, /// - /// B2D3 - This tag defines a colour transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and + /// B2D3 - This tag defines a color transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and /// provides a means to override the BToA1 tag. /// BToD3 = 0x42324433, @@ -97,8 +97,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc CharTarget = 0x74617267, /// - /// chad - This tag contains a matrix, which shall be invertible, and which converts an nCIEXYZ colour, measured using the actual illumination - /// conditions and relative to the actual adopted white, to an nCIEXYZ colour relative to the PCS adopted white + /// chad - This tag contains a matrix, which shall be invertible, and which converts an nCIEXYZ color, measured using the actual illumination + /// conditions and relative to the actual adopted white, to an nCIEXYZ color relative to the PCS adopted white /// ChromaticAdaptation = 0x63686164, @@ -166,33 +166,33 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc DeviceSettings = 0x64657673, /// - /// D2B0 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded + /// D2B0 - This tag defines a color transform from Device to PCS. It supports float32Number-encoded /// input range, output range and transform, and provides a means to override the AToB0 tag /// DToB0 = 0x44324230, /// - /// D2B1 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded + /// D2B1 - This tag defines a color transform from Device to PCS. It supports float32Number-encoded /// input range, output range and transform, and provides a means to override the AToB1 tag /// DToB1 = 0x44324230, /// - /// D2B2 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded + /// D2B2 - This tag defines a color transform from Device to PCS. It supports float32Number-encoded /// input range, output range and transform, and provides a means to override the AToB1 tag /// DToB2 = 0x44324230, /// - /// D2B3 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded + /// D2B3 - This tag defines a color transform from Device to PCS. It supports float32Number-encoded /// input range, output range and transform, and provides a means to override the AToB1 tag /// DToB3 = 0x44324230, /// /// gamt - This tag provides a table in which PCS values are the input and a single - /// output value for each input value is the output. If the output value is 0, the PCS colour is in-gamut. - /// If the output is non-zero, the PCS colour is out-of-gamut + /// output value for each input value is the output. If the output value is 0, the PCS color is in-gamut. + /// If the output is non-zero, the PCS color is out-of-gamut /// Gamut = 0x67616D74, @@ -214,7 +214,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc GreenTrc = 0x67545243, /// - /// lumi - This tag contains the absolute luminance of emissive devices in candelas per square metre as described by the Y channel. + /// lumi - This tag contains the absolute luminance of emissive devices in candelas per square meter as described by the Y channel. /// Luminance = 0x6C756d69, @@ -240,8 +240,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc NamedColor = 0x6E636f6C, /// - /// ncl2 - This tag contains the named colour information providing a PCS and optional device representation - /// for a list of named colours. + /// ncl2 - This tag contains the named color information providing a PCS and optional device representation + /// for a list of named colors. /// NamedColor2 = 0x6E636C32, diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccRenderingIntent.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccRenderingIntent.cs index e0504b24cb..7cb9c00f39 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccRenderingIntent.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccRenderingIntent.cs @@ -10,11 +10,11 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc { /// /// In perceptual transforms the PCS values represent hypothetical - /// measurements of a colour reproduction on the reference reflective + /// measurements of a color reproduction on the reference reflective /// medium. By extension, for the perceptual intent, the PCS represents /// the appearance of that reproduction as viewed in the reference viewing /// environment by a human observer adapted to that environment. The exact - /// colour rendering of the perceptual intent is vendor specific. + /// color rendering of the perceptual intent is vendor specific. /// Perceptual = 0, @@ -27,15 +27,15 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc MediaRelativeColorimetric = 1, /// - /// The exact colour rendering of the saturation intent is vendor + /// The exact color rendering of the saturation intent is vendor /// specific and involves compromises such as trading off - /// preservation of hue in order to preserve the vividness of pure colours. + /// preservation of hue in order to preserve the vividness of pure colors. /// Saturation = 2, /// /// Transformations for this intent shall leave the chromatically - /// adapted nCIEXYZ tristimulus values of the in-gamut colours unchanged. + /// adapted nCIEXYZ tristimulus values of the in-gamut colors unchanged. /// AbsoluteColorimetric = 3, } diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs index 1493ecc6bb..ad0db4df93 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// This is an optional tag which specifies the laydown order in which colorants /// will be printed on an n-colorant device. The laydown order may be the same /// as the channel generation order listed in the colorantTableTag or the channel - /// order of a colour encoding type such as CMYK, in which case this tag is not + /// order of a color encoding type such as CMYK, in which case this tag is not /// needed. When this is not the case (for example, ink-towers sometimes use /// the order KCMY), this tag may be used to specify the laydown order of the /// colorants @@ -59,25 +59,25 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc DateTime = 0x6474696D, /// - /// This structure represents a colour transform using tables with 16-bit + /// This structure represents a color transform using tables with 16-bit /// precision. This type contains four processing elements: a 3 × 3 matrix - /// (which shall be the identity matrix unless the input colour space is + /// (which shall be the identity matrix unless the input color space is /// PCSXYZ), a set of one-dimensional input tables, a multi-dimensional /// lookup table, and a set of one-dimensional output tables /// Lut16 = 0x6D667432, /// - /// This structure represents a colour transform using tables of 8-bit + /// This structure represents a color transform using tables of 8-bit /// precision. This type contains four processing elements: a 3 × 3 matrix - /// (which shall be the identity matrix unless the input colour space is + /// (which shall be the identity matrix unless the input color space is /// PCSXYZ), a set of one-dimensional input tables, a multi-dimensional /// lookup table, and a set of one-dimensional output tables. /// Lut8 = 0x6D667431, /// - /// This structure represents a colour transform. The type contains up + /// This structure represents a color transform. The type contains up /// to five processing elements which are stored in the AToBTag tag /// in the following order: a set of one-dimensional curves, a 3 × 3 /// matrix with offset terms, a set of one-dimensional curves, a @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc LutAToB = 0x6D414220, /// - /// This structure represents a colour transform. The type contains + /// This structure represents a color transform. The type contains /// up to five processing elements which are stored in the BToATag /// in the following order: a set of one-dimensional curves, a 3 × 3 /// matrix with offset terms, a set of one-dimensional curves, a @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc MultiLocalizedUnicode = 0x6D6C7563, /// - /// This structure represents a colour transform, containing a sequence + /// This structure represents a color transform, containing a sequence /// of processing elements. The processing elements contained in the /// structure are defined in the structure itself, allowing for a flexible /// structure. Currently supported processing elements are: a set of one @@ -123,15 +123,15 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc MultiProcessElements = 0x6D706574, /// - /// This type is a count value and array of structures that provide colour - /// coordinates for colour names. For each named colour, a PCS and optional - /// device representation of the colour are given. Both representations are + /// This type is a count value and array of structures that provide color + /// coordinates for color names. For each named color, a PCS and optional + /// device representation of the color are given. Both representations are /// 16-bit values and PCS values shall be relative colorimetric. The device - /// representation corresponds to the header’s "data colour space" field. + /// representation corresponds to the header’s "data color space" field. /// This representation should be consistent with the "number of device /// coordinates" field in the namedColor2Type. If this field is 0, device /// coordinates are not provided. The PCS representation corresponds to the - /// header's PCS field. The PCS representation is always provided. Colour + /// header's PCS field. The PCS representation is always provided. Color /// names are fixed-length, 32-byte fields including null termination. In /// order to maintain maximum portability, it is strongly recommended that /// special characters of the 7-bit ASCII set not be used. @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// so that corrections can be made for variation in the device without /// having to produce a new profile. The mechanism can be used by applications /// to allow users with relatively inexpensive and readily available - /// instrumentation to apply corrections to individual output colour + /// instrumentation to apply corrections to individual output color /// channels in order to achieve consistent results. /// ResponseCurveSet16 = 0x72637332, diff --git a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs index 2ed3164097..2572b32933 100644 --- a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The hexadecimal representation of the combined color components arranged /// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax. /// - /// Returns a that represents the color defined by the provided RGBA heax string. + /// Returns a that represents the color defined by the provided RGBA hex string. public static TPixel FromHex(string hex) { Guard.NotNullOrWhiteSpace(hex, nameof(hex)); diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index f4eb19be33..115dd7a43d 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -110,7 +110,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); // Gray8 and Gray16 are special implementations of IPixel in that they do not conform to the - // standard RGBA colorspace format and must be converted from RGBA using the special ITU BT709 alogrithm. + // standard RGBA colorspace format and must be converted from RGBA using the special ITU BT709 algorithm. // One of the requirements of FromScaledVector4/ToScaledVector4 is that it unaware of this and // packs/unpacks the pixel without and conversion so we employ custom methods do do this. if (typeof(TDestinationPixel) == typeof(Gray16)) diff --git a/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs b/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs index 55a94fc81e..12ec389b06 100644 --- a/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs +++ b/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils // packedRgba = [aa bb gg rr] // tmp1 = [aa 00 gg 00] // tmp2 = [00 bb 00 rr] - // tmp3=ROTL(16, tmp2) = [00 rr 00 bb] + // tmp3=ROTL(16, tmp2) = [00 rr 00 bb] // tmp1 + tmp3 = [aa rr gg bb] uint tmp1 = packedRgba & 0xFF00FF00; uint tmp2 = packedRgba & 0x00FF00FF; diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs index 7c57fe4fbd..5609e606d8 100644 --- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils Span lastQuarterOfDestBuffer = MemoryMarshal.Cast(destVectors).Slice((3 * count) + 1, countWithoutLastItem); pixelOperations.ToRgba32(configuration, reducedSource, lastQuarterOfDestBuffer); - // 'destVectors' and 'lastQuarterOfDestBuffer' are ovelapping buffers, + // 'destVectors' and 'lastQuarterOfDestBuffer' are overlapping buffers, // but we are always reading/writing at different positions: SimdUtils.BulkConvertByteToNormalizedFloat( MemoryMarshal.Cast(lastQuarterOfDestBuffer), From 99f06f7657eee5e186a683b0c51b277a3335d7ea Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 15:07:06 +0100 Subject: [PATCH 306/381] fix typo in comment --- src/ImageSharp/Formats/Png/Filters/PaethFilter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs b/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs index 4ffc39bdbd..4cd61e043d 100644 --- a/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters ref byte prevBaseRef = ref MemoryMarshal.GetReference(previousScanline); // Paeth(x) + PaethPredictor(Raw(x-bpp), Prior(x), Prior(x-bpp)) - int offset = bytesPerPixel + 1; // Add one bcause x starts at one. + int offset = bytesPerPixel + 1; // Add one because x starts at one. int x = 1; for (; x < offset; x++) { From e42cf0cd6993c2998f18f1d494a9920bcd413bd2 Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Mon, 5 Nov 2018 16:55:48 -0600 Subject: [PATCH 307/381] ImageSharp-762_Aot-compiling: whitespace cleanup --- src/ImageSharp/Advanced/AotCompiler.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Advanced/AotCompiler.cs b/src/ImageSharp/Advanced/AotCompiler.cs index 1c7f12ef7b..406c162ad5 100644 --- a/src/ImageSharp/Advanced/AotCompiler.cs +++ b/src/ImageSharp/Advanced/AotCompiler.cs @@ -63,9 +63,9 @@ namespace SixLabors.ImageSharp.Advanced /// If you are running ImageSharp on iOS and try to call SaveAsGif, it will throw an excepion: /// "Attempting to JIT compile method... OctreeFrameQuantizer.ConstructPalette... while running in aot-only mode." /// The reason this happens is the SaveAsGif method makes haevy use of generics, which are too confusing for the AoT - /// compiler used on Xamarin.iOS. It spins up the JIT compiler to try and figure it out, but that is an illegal op on - /// iOS so it bombs out. - /// If you are getting the above error, you need to call this method, which will pre-seed the AoT compiler with the + /// compiler used on Xamarin.iOS. It spins up the JIT compiler to try and figure it out, but that is an illegal op on + /// iOS so it bombs out. + /// If you are getting the above error, you need to call this method, which will pre-seed the AoT compiler with the /// necessary methods to complete the SaveAsGif call. That's it, otherwise you should NEVER need this method!!! /// /// The pixel format. From 45fd99983a2db2f47ee240ee9e913a5b48b28df8 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 5 Nov 2018 19:21:16 -0800 Subject: [PATCH 308/381] Fix infinate loop when a GIF prematurely terminates in Skip --- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 29 ++++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index b8a270b3f5..bfa91416aa 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -142,8 +142,7 @@ namespace SixLabors.ImageSharp.Formats.Gif this.ReadApplicationExtension(); break; case GifConstants.PlainTextLabel: - int plainLength = stream.ReadByte(); - this.Skip(plainLength); // Not supported by any known decoder. + this.SkipBlock(); // Not supported by any known decoder. break; } } @@ -190,9 +189,7 @@ namespace SixLabors.ImageSharp.Formats.Gif switch (stream.ReadByte()) { case GifConstants.GraphicControlLabel: - - // Skip graphic control extension block - this.Skip(0); + this.SkipBlock(); // Skip graphic control extension block break; case GifConstants.CommentLabel: this.ReadComments(); @@ -201,8 +198,7 @@ namespace SixLabors.ImageSharp.Formats.Gif this.ReadApplicationExtension(); break; case GifConstants.PlainTextLabel: - int plainLength = stream.ReadByte(); - this.Skip(plainLength); // Not supported by any known decoder. + this.SkipBlock(); // Not supported by any known decoder. break; } } @@ -288,24 +284,27 @@ namespace SixLabors.ImageSharp.Formats.Gif // Could be XMP or something else not supported yet. // Back up and skip. this.stream.Position -= appLength + 1; - this.Skip(appLength); + this.SkipBlock(appLength); return; } - this.Skip(appLength); // Not supported by any known decoder. + this.SkipBlock(appLength); // Not supported by any known decoder. } /// - /// Skips the designated number of bytes in the stream. + /// Skips over a block or reads its terminator. + /// The length of the block to skip. /// - /// The number of bytes to skip. - private void Skip(int length) + private void SkipBlock(int blockSize = 0) { - this.stream.Skip(length); + if (blockSize > 0) + { + this.stream.Skip(blockSize); + } int flag; - while ((flag = this.stream.ReadByte()) != 0) + while ((flag = this.stream.ReadByte()) > 0) { this.stream.Skip(flag); } @@ -370,7 +369,7 @@ namespace SixLabors.ImageSharp.Formats.Gif this.ReadFrameColors(ref image, ref previousFrame, indices.GetSpan(), colorTable, this.imageDescriptor); // Skip any remaining blocks - this.Skip(0); + this.SkipBlock(); } finally { From 74e3a3505cead90b4b2c10cfc905d4a7bb8a5709 Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Tue, 6 Nov 2018 09:46:14 -0600 Subject: [PATCH 309/381] ImageSharp-762_Aot-compiling: clean up AotGetPalette method --- .../Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs index 8f688e8387..dd56375f63 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs @@ -136,7 +136,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } } - internal TPixel[] AotGetPalette() => this.octree.Palletize(this.colors); + internal TPixel[] AotGetPalette() => this.GetPalette(); /// protected override TPixel[] GetPalette() => this.octree.Palletize(this.colors); From fdb45dda5e350e342d67af9e30c112c98d8e6aec Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 6 Nov 2018 08:40:08 -0800 Subject: [PATCH 310/381] Add test coverage for #770 --- .../ImageSharp.Sandbox46.csproj | 2 +- .../Formats/Gif/GifDecoderTests.cs | 33 +++++++++++++++---- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index bb559b70dd..4d7b7de759 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -11,7 +11,7 @@ James Jackson-South and contributors James Jackson-South SixLabors.ImageSharp.Sandbox46 - 7.2 + 7.3 diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs index 6d2a74c03b..5bfbb058be 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs @@ -1,20 +1,20 @@ // 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; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats.Gif; +using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using Xunit; -using System.IO; -using SixLabors.ImageSharp.Advanced; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Formats.Gif { - using System.Collections.Generic; - using SixLabors.ImageSharp.MetaData; - using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; - public class GifDecoderTests { private const PixelTypes TestPixelTypes = PixelTypes.Rgba32 | PixelTypes.RgbaVector | PixelTypes.Argb32; @@ -70,6 +70,27 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif } } + [Fact] + public unsafe void Decode_NonTerminatedFinalFrame() + { + var testFile = TestFile.Create(TestImages.Gif.Rings); + + int length = testFile.Bytes.Length - 2; + + fixed (byte* data = testFile.Bytes.AsSpan(0, length)) + { + using (var stream = new UnmanagedMemoryStream(data, length)) + { + var decoder = new GifDecoder(); + + using (Image image = decoder.Decode(Configuration.Default, stream)) + { + Assert.Equal((200, 200), (image.Width, image.Height)); + } + } + } + } + [Theory] [MemberData(nameof(RatioFiles))] public void Decode_VerifyRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit) From dfc926e5692cadfc5c5b0d3b59cdcea9225ba7fe Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 6 Nov 2018 17:27:21 +0000 Subject: [PATCH 311/381] Better Rotate --- .../Transforms/AffineTransformProcessor.cs | 204 ++++----------- .../Transforms/AffineTransformProcessorOld.cs | 239 ++++++++++++++++++ .../CenteredAffineTransformProcessor.cs | 2 +- .../Processors/Transforms/RotateProcessor.cs | 16 +- .../Transforms/TransformKernelMap.cs | 188 ++++++++++++++ .../Processors/Transforms/TransformUtils.cs | 121 +++++++++ .../Processing/TransformExtensions.cs | 6 +- 7 files changed, 611 insertions(+), 165 deletions(-) create mode 100644 src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessorOld.cs create mode 100644 src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs create mode 100644 src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index e12b91eab9..edddab1811 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -5,13 +5,9 @@ using System; using System.Collections.Generic; using System.Linq; using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; 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.Transforms @@ -20,29 +16,42 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// Provides the base methods to perform affine transforms on an image. /// /// The pixel format. - internal class AffineTransformProcessor : InterpolatedTransformProcessorBase + internal class AffineTransformProcessor : TransformProcessorBase where TPixel : struct, IPixel { + private readonly Rectangle transformedRectangle; + /// /// Initializes a new instance of the class. /// /// The transform matrix /// The sampler to perform the transform operation. - /// The target dimensions to constrain the transformed image to. - public AffineTransformProcessor(Matrix3x2 matrix, IResampler sampler, Size targetDimensions) - : base(sampler) + /// The source image size + public AffineTransformProcessor(Matrix3x2 matrix, IResampler sampler, Size sourceSize) { + Guard.NotNull(sampler, nameof(sampler)); + this.Sampler = sampler; this.TransformMatrix = matrix; - this.TargetDimensions = targetDimensions; + this.transformedRectangle = TransformUtils.GetTransformedRectangle( + new Rectangle(Point.Empty, sourceSize), + matrix); + + // We want to resize the canvas here taking into account any translations. + this.TargetDimensions = new Size(this.transformedRectangle.Right, this.transformedRectangle.Bottom); } /// - /// Gets the matrix used to supply the affine transform + /// Gets the sampler to perform interpolation of the transform operation. + /// + public IResampler Sampler { get; } + + /// + /// Gets the matrix used to supply the affine transform. /// public Matrix3x2 TransformMatrix { get; } /// - /// Gets the target dimensions to constrain the transformed image to + /// Gets the target dimensions to constrain the transformed image to. /// public Size TargetDimensions { get; } @@ -68,13 +77,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int width = this.TargetDimensions.Width; Rectangle sourceBounds = source.Bounds(); - var targetBounds = new Rectangle(0, 0, width, height); - - // Since could potentially be resizing the canvas we might need to re-calculate the matrix - Matrix3x2 matrix = this.GetProcessingMatrix(sourceBounds, targetBounds); + var targetBounds = new Rectangle(Point.Empty, this.TargetDimensions); // Convert from screen to world space. - Matrix3x2.Invert(matrix, out matrix); + Matrix3x2.Invert(this.TransformMatrix, out Matrix3x2 matrix); if (this.Sampler is NearestNeighborResampler) { @@ -82,158 +88,52 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms targetBounds, configuration, rows => + { + for (int y = rows.Min; y < rows.Max; y++) { - for (int y = rows.Min; y < rows.Max; y++) - { - Span destRow = destination.GetPixelRowSpan(y); + Span destRow = destination.GetPixelRowSpan(y); - for (int x = 0; x < width; x++) + for (int x = 0; x < width; x++) + { + var point = Point.Transform(new Point(x, y), matrix); + if (sourceBounds.Contains(point.X, point.Y)) { - var point = Point.Transform(new Point(x, y), matrix); - if (sourceBounds.Contains(point.X, point.Y)) - { - destRow[x] = source[point.X, point.Y]; - } + destRow[x] = source[point.X, point.Y]; } } - }); + } + }); return; } - int maxSourceX = source.Width - 1; - int maxSourceY = source.Height - 1; - (float radius, float scale, float ratio) xRadiusScale = this.GetSamplingRadius(source.Width, destination.Width); - (float radius, float scale, float ratio) yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height); - float xScale = xRadiusScale.scale; - float yScale = yRadiusScale.scale; - var radius = new Vector2(xRadiusScale.radius, yRadiusScale.radius); - IResampler sampler = this.Sampler; - var maxSource = new Vector4(maxSourceX, maxSourceY, maxSourceX, maxSourceY); - int xLength = (int)MathF.Ceiling((radius.X * 2) + 2); - int yLength = (int)MathF.Ceiling((radius.Y * 2) + 2); - - MemoryAllocator memoryAllocator = configuration.MemoryAllocator; - - using (Buffer2D yBuffer = memoryAllocator.Allocate2D(yLength, height)) - using (Buffer2D xBuffer = memoryAllocator.Allocate2D(xLength, height)) + using (var kernel = new TransformKernelMap(configuration, source.Size(), destination.Size(), this.Sampler)) { - ParallelHelper.IterateRows( + ParallelHelper.IterateRowsWithTempBuffer( targetBounds, configuration, - rows => + (rows, vectorBuffer) => + { + Span vectorSpan = vectorBuffer.Span; + for (int y = rows.Min; y < rows.Max; y++) { - for (int y = rows.Min; y < rows.Max; 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)); + Span targetRowSpan = destination.GetPixelRowSpan(y); + PixelOperations.Instance.ToVector4(configuration, targetRowSpan, vectorSpan); + ref float ySpanRef = ref kernel.GetYStartReference(y); + ref float xSpanRef = ref kernel.GetXStartReference(y); - for (int x = 0; x < width; x++) - { - // 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; - } - - // 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); - } - - // 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); - - // Values are first premultiplied to prevent darkening of edge pixels - 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 - Vector4Utils.UnPremultiply(ref sum); - dest.FromVector4(sum); - } + for (int x = 0; x < width; x++) + { + // 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); + kernel.Convolve(point, x, ref ySpanRef, ref xSpanRef, source.PixelBuffer, vectorSpan); } - }); + + PixelOperations.Instance.FromVector4(configuration, vectorSpan, targetRowSpan); + } + }); } } - - /// - /// Gets a transform matrix adjusted for final processing based upon the target image bounds. - /// - /// The source image bounds. - /// The destination image bounds. - /// - /// The . - /// - protected virtual Matrix3x2 GetProcessingMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle) - => this.TransformMatrix; } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessorOld.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessorOld.cs new file mode 100644 index 0000000000..5891afd9a6 --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessorOld.cs @@ -0,0 +1,239 @@ +// 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 System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +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.Transforms +{ + /// + /// Provides the base methods to perform affine transforms on an image. + /// + /// The pixel format. + internal class AffineTransformProcessorOld : InterpolatedTransformProcessorBase + where TPixel : struct, IPixel + { + /// + /// Initializes a new instance of the class. + /// + /// The transform matrix + /// The sampler to perform the transform operation. + /// The target dimensions to constrain the transformed image to. + public AffineTransformProcessorOld(Matrix3x2 matrix, IResampler sampler, Size targetDimensions) + : base(sampler) + { + this.TransformMatrix = matrix; + this.TargetDimensions = targetDimensions; + } + + /// + /// Gets the matrix used to supply the affine transform + /// + public Matrix3x2 TransformMatrix { get; } + + /// + /// Gets the target dimensions to constrain the transformed image to + /// + public Size TargetDimensions { get; } + + /// + 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.TargetDimensions, x.MetaData.DeepClone())); + + // Use the overload to prevent an extra frame being added + return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); + } + + /// + protected override void OnFrameApply( + ImageFrame source, + ImageFrame destination, + Rectangle sourceRectangle, + Configuration configuration) + { + int height = this.TargetDimensions.Height; + int width = this.TargetDimensions.Width; + + Rectangle sourceBounds = source.Bounds(); + var targetBounds = new Rectangle(0, 0, width, height); + + // Since could potentially be resizing the canvas we might need to re-calculate the matrix + Matrix3x2 matrix = this.GetProcessingMatrix(sourceBounds, targetBounds); + + // Convert from screen to world space. + Matrix3x2.Invert(matrix, out matrix); + + if (this.Sampler is NearestNeighborResampler) + { + ParallelHelper.IterateRows( + targetBounds, + configuration, + rows => + { + for (int y = rows.Min; y < rows.Max; 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; + } + + int maxSourceX = source.Width - 1; + int maxSourceY = source.Height - 1; + (float radius, float scale, float ratio) xRadiusScale = this.GetSamplingRadius(source.Width, destination.Width); + (float radius, float scale, float ratio) yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height); + float xScale = xRadiusScale.scale; + float yScale = yRadiusScale.scale; + var radius = new Vector2(xRadiusScale.radius, yRadiusScale.radius); + IResampler sampler = this.Sampler; + var maxSource = new Vector4(maxSourceX, maxSourceY, maxSourceX, maxSourceY); + int xLength = (int)MathF.Ceiling((radius.X * 2) + 2); + int yLength = (int)MathF.Ceiling((radius.Y * 2) + 2); + + MemoryAllocator memoryAllocator = configuration.MemoryAllocator; + + using (Buffer2D yBuffer = memoryAllocator.Allocate2D(yLength, height)) + using (Buffer2D xBuffer = memoryAllocator.Allocate2D(xLength, height)) + { + ParallelHelper.IterateRows( + targetBounds, + configuration, + rows => + { + for (int y = rows.Min; y < rows.Max; 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++) + { + // 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; + } + + // 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); + } + + // 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); + + // Values are first premultiplied to prevent darkening of edge pixels + 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 + Vector4Utils.UnPremultiply(ref sum); + dest.FromVector4(sum); + } + } + }); + } + } + + /// + /// Gets a transform matrix adjusted for final processing based upon the target image bounds. + /// + /// The source image bounds. + /// The destination image bounds. + /// + /// The . + /// + protected virtual Matrix3x2 GetProcessingMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle) + => this.TransformMatrix; + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs index adaee17665..82614dc8c2 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// A base class that provides methods to allow the automatic centering of affine transforms /// /// The pixel format. - internal abstract class CenteredAffineTransformProcessor : AffineTransformProcessor + internal abstract class CenteredAffineTransformProcessor : AffineTransformProcessorOld where TPixel : struct, IPixel { /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs index 2ad626755c..cbf82cc9b0 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs @@ -2,12 +2,10 @@ // Licensed under the Apache License, Version 2.0. 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; namespace SixLabors.ImageSharp.Processing.Processors.Transforms @@ -16,7 +14,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// Provides methods that allow the rotating of images. /// /// The pixel format. - internal class RotateProcessor : CenteredAffineTransformProcessor + internal class RotateProcessor : AffineTransformProcessor where TPixel : struct, IPixel { /// @@ -36,10 +34,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The sampler to perform the rotating operation. /// The source image size public RotateProcessor(float degrees, IResampler sampler, Size sourceSize) - : base(Matrix3x2Extensions.CreateRotationDegrees(degrees, PointF.Empty), sampler, sourceSize) - { - this.Degrees = degrees; - } + : base( + TransformUtils.CreateCenteredRotationMatrixDegrees(degrees, sourceSize), + sampler, + sourceSize) + => this.Degrees = degrees; /// /// Gets the angle of rotation in degrees. @@ -84,7 +83,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The private static float WrapDegrees(float degrees) { - degrees = degrees % 360; + degrees %= 360; while (degrees < 0) { @@ -223,7 +222,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms 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]; diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs new file mode 100644 index 0000000000..5acc7213cb --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs @@ -0,0 +1,188 @@ +// 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.Memory; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; + +// TODO: It would be great if we could somehow optimize this to calculate the weights once. +// currently we cannot do that as we are calulating the weight of the transformed point dimension +// not the point in the original image. +namespace SixLabors.ImageSharp.Processing.Processors.Transforms +{ + /// + /// Contains the methods required to calculate kernel sampling weights on-the-fly. + /// + internal class TransformKernelMap : IDisposable + { + private readonly Buffer2D yBuffer; + private readonly Buffer2D xBuffer; + private readonly float yScale; + private readonly float xScale; + private readonly int yLength; + private readonly int xLength; + private readonly Vector2 extents; + private Vector4 maxSourceExtents; + private readonly IResampler sampler; + + /// + /// Initializes a new instance of the class. + /// + /// The configuration. + /// The source size. + /// The destination size. + /// The sampler. + public TransformKernelMap(Configuration configuration, Size source, Size destination, IResampler sampler) + { + this.sampler = sampler; + (float radius, float scale) yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height); + (float radius, float scale) xRadiusScale = this.GetSamplingRadius(source.Width, destination.Width); + + this.yScale = yRadiusScale.scale; + this.xScale = xRadiusScale.scale; + this.extents = new Vector2(xRadiusScale.radius, yRadiusScale.radius); + this.xLength = (int)MathF.Ceiling((this.extents.X * 2) + 2); + this.yLength = (int)MathF.Ceiling((this.extents.Y * 2) + 2); + + // We use 2D buffers so that we can access the weight spans in parallel. + this.yBuffer = configuration.MemoryAllocator.Allocate2D(this.yLength, destination.Height); + this.xBuffer = configuration.MemoryAllocator.Allocate2D(this.xLength, destination.Height); + + int maxX = source.Width - 1; + int maxY = source.Height - 1; + this.maxSourceExtents = new Vector4(maxX, maxY, maxX, maxY); + } + + /// + /// Gets a reference to the first item of the y window. + /// + /// The reference to the first item of the window. + [MethodImpl(InliningOptions.ShortMethod)] + public ref float GetYStartReference(int y) + => ref MemoryMarshal.GetReference(this.yBuffer.GetRowSpan(y)); + + /// + /// Gets a reference to the first item of the x window. + /// + /// The reference to the first item of the window. + [MethodImpl(InliningOptions.ShortMethod)] + public ref float GetXStartReference(int y) + => ref MemoryMarshal.GetReference(this.xBuffer.GetRowSpan(y)); + + public void Convolve( + Vector2 transformedPoint, + int column, + ref float ySpanRef, + ref float xSpanRef, + Buffer2D sourcePixels, + Span targetRow) + where TPixel : struct, IPixel + { + // Clamp sampling pixel radial extents to the source image edges + Vector2 minXY = transformedPoint - this.extents; + Vector2 maxXY = transformedPoint + this.extents; + + // minX, minY, maxX, maxY + var extents = new Vector4( + MathF.Ceiling(minXY.X - .5F), + MathF.Ceiling(minXY.Y - .5F), + MathF.Floor(maxXY.X + .5F), + MathF.Floor(maxXY.Y + .5F)); + + int left = (int)extents.X; + int top = (int)extents.Y; + int right = (int)extents.Z; + int bottom = (int)extents.W; + + extents = Vector4.Clamp(extents, Vector4.Zero, this.maxSourceExtents); + + int minX = (int)extents.X; + int minY = (int)extents.Y; + int maxX = (int)extents.Z; + int maxY = (int)extents.W; + + if (minX == maxX || minY == maxY) + { + return; + } + + // TODO: Get Anton to use his superior brain on this one. + // It looks to me like we're calculating the same weights over and over again + // since min(X+Y) and max(X+Y) are the same distance apart. + this.CalculateWeights(minY, maxY, maxY - minY, transformedPoint.Y, ref ySpanRef); + this.CalculateWeights(minX, maxX, maxX - minX, transformedPoint.X, ref xSpanRef); + + Vector4 sum = Vector4.Zero; + for (int kernelY = 0, y = minY; y <= maxY; y++, kernelY++) + { + float yWeight = Unsafe.Add(ref ySpanRef, kernelY); + + for (int kernelX = 0, x = minX; x <= maxX; x++, kernelX++) + { + float xWeight = Unsafe.Add(ref xSpanRef, kernelX); + + // Values are first premultiplied to prevent darkening of edge pixels. + var current = sourcePixels[x, y].ToVector4(); + Vector4Utils.Premultiply(ref current); + sum += current * xWeight * yWeight; + } + } + + // Reverse the premultiplication + Vector4Utils.UnPremultiply(ref sum); + targetRow[column] = sum; + } + + /// + /// Calculated the normalized weights for the given point. + /// + /// The minimum sampling offset + /// The maximum sampling offset + /// The length of the weights collection + /// The transformed point dimension + /// The reference to the collection of weights + [MethodImpl(InliningOptions.ShortMethod)] + private void CalculateWeights(int min, int max, int length, float point, ref float weightsRef) + { + float sum = 0; + for (int x = 0, i = min; i <= max; i++, x++) + { + float weight = this.sampler.GetValue(i - point); + sum += weight; + Unsafe.Add(ref weightsRef, x) = this.sampler.GetValue(i - point); + } + + // TODO: Do we need this? Check what happens when we scale an image down. + // if (sum > 0) + // { + // for (int i = 0; i < length; i++) + // { + // ref float wRef = ref Unsafe.Add(ref weightsRef, i); + // wRef /= sum; + // } + // } + } + + private (float radius, float scale) GetSamplingRadius(int sourceSize, int destinationSize) + { + float scale = (float)sourceSize / destinationSize; + + if (scale < 1F) + { + scale = 1F; + } + + return (MathF.Ceiling(scale * this.sampler.Radius), scale); + } + + public void Dispose() + { + this.yBuffer?.Dispose(); + this.xBuffer?.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs new file mode 100644 index 0000000000..7d03502499 --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs @@ -0,0 +1,121 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing.Processors.Transforms +{ + /// + /// Contains utility methods for working with transforms. + /// + public static class TransformUtils + { + /// + /// Creates a centered rotation matrix using the given rotation in degrees and the source size. + /// + /// The amount of rotation, in degrees. + /// The source image size. + /// The . + public static Matrix3x2 CreateCenteredRotationMatrixDegrees(float degrees, Size size) + => CreateCenteredTransformMatrix( + new Rectangle(Point.Empty, size), + Matrix3x2Extensions.CreateRotationDegrees(degrees, PointF.Empty)); + + /// + /// Gets the centered transform matrix based upon the source and destination rectangles. + /// + /// The source image bounds. + /// The transformation matrix. + /// The + public static Matrix3x2 CreateCenteredTransformMatrix(Rectangle sourceRectangle, Matrix3x2 matrix) + { + Rectangle destinationRectangle = GetTransformedBoundingRectangle(sourceRectangle, matrix); + + // We invert the matrix to handle the transformation from screen to world space. + // This ensures scaling matrices are correct. + Matrix3x2.Invert(matrix, out Matrix3x2 inverted); + + var translationToTargetCenter = Matrix3x2.CreateTranslation(new Vector2(-destinationRectangle.Width, -destinationRectangle.Height) * .5F); + var translateToSourceCenter = Matrix3x2.CreateTranslation(new Vector2(sourceRectangle.Width, sourceRectangle.Height) * .5F); + + // Translate back to world space. + Matrix3x2.Invert(translationToTargetCenter * inverted * translateToSourceCenter, out Matrix3x2 centered); + + return centered; + } + + /// + /// Gets the centered transform matrix based upon the source and destination rectangles. + /// + /// The source image bounds. + /// The destination image bounds. + /// The transformation matrix. + /// The + public static Matrix3x2 GetCenteredTransformMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle, Matrix3x2 matrix) + { + // We invert the matrix to handle the transformation from screen to world space. + // This ensures scaling matrices are correct. + Matrix3x2.Invert(matrix, out Matrix3x2 inverted); + + var translationToTargetCenter = Matrix3x2.CreateTranslation(new Vector2(-destinationRectangle.Width, -destinationRectangle.Height) * .5F); + var translateToSourceCenter = Matrix3x2.CreateTranslation(new Vector2(sourceRectangle.Width, sourceRectangle.Height) * .5F); + + // Translate back to world space. + Matrix3x2.Invert(translationToTargetCenter * inverted * translateToSourceCenter, out Matrix3x2 centered); + + return centered; + } + + /// + /// Returns the rectangle bounds relative to the source for the given transformation matrix. + /// + /// The source rectangle. + /// The transformation matrix. + /// + /// The . + /// + public static Rectangle GetTransformedBoundingRectangle(Rectangle rectangle, Matrix3x2 matrix) + { + Rectangle transformed = GetTransformedRectangle(rectangle, matrix); + + // TODO: Check this. + return new Rectangle(0, 0, transformed.Width, transformed.Height); + } + + /// + /// Returns the rectangle relative to the source for the given transformation matrix. + /// + /// The source rectangle. + /// The transformation matrix. + /// + /// The . + /// + public static Rectangle GetTransformedRectangle(Rectangle rectangle, Matrix3x2 matrix) + { + if (rectangle.Equals(default) || Matrix3x2.Identity.Equals(matrix)) + { + return rectangle; + } + + var tl = Vector2.Transform(new Vector2(rectangle.Left, rectangle.Top), matrix); + var tr = Vector2.Transform(new Vector2(rectangle.Right, rectangle.Top), matrix); + var bl = Vector2.Transform(new Vector2(rectangle.Left, rectangle.Bottom), matrix); + var br = Vector2.Transform(new Vector2(rectangle.Right, rectangle.Bottom), matrix); + + return GetBoundingRectangle(tl, tr, bl, br); + } + + private static Rectangle GetBoundingRectangle(Vector2 tl, Vector2 tr, Vector2 bl, Vector2 br) + { + // Find the minimum and maximum "corners" based on the given vectors + float left = MathF.Min(tl.X, MathF.Min(tr.X, MathF.Min(bl.X, br.X))); + float top = MathF.Min(tl.Y, MathF.Min(tr.Y, MathF.Min(bl.Y, br.Y))); + float right = MathF.Max(tl.X, MathF.Max(tr.X, MathF.Max(bl.X, br.X))); + float bottom = MathF.Max(tl.Y, MathF.Max(tr.Y, MathF.Max(bl.Y, br.Y))); + + return Rectangle.Round(RectangleF.FromLTRB(left, top, right, bottom)); + } + } +} diff --git a/src/ImageSharp/Processing/TransformExtensions.cs b/src/ImageSharp/Processing/TransformExtensions.cs index 0ec1e295d9..3f24969a3d 100644 --- a/src/ImageSharp/Processing/TransformExtensions.cs +++ b/src/ImageSharp/Processing/TransformExtensions.cs @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Processing /// The public static IImageProcessingContext Transform(this IImageProcessingContext source, Matrix3x2 matrix, IResampler sampler) where TPixel : struct, IPixel - => source.ApplyProcessor(new AffineTransformProcessor(matrix, sampler, source.GetCurrentSize())); + => source.ApplyProcessor(new AffineTransformProcessorOld(matrix, sampler, source.GetCurrentSize())); /// /// Transforms an image by the given matrix using the specified sampling algorithm @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing { var t = Matrix3x2.CreateTranslation(-rectangle.Location); Matrix3x2 combinedMatrix = t * matrix; - return source.ApplyProcessor(new AffineTransformProcessor(combinedMatrix, sampler, rectangle.Size)); + return source.ApplyProcessor(new AffineTransformProcessorOld(combinedMatrix, sampler, rectangle.Size)); } /// @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Processing IResampler sampler, Size destinationSize) where TPixel : struct, IPixel - => source.ApplyProcessor(new AffineTransformProcessor(matrix, sampler, destinationSize)); + => source.ApplyProcessor(new AffineTransformProcessorOld(matrix, sampler, destinationSize)); /// /// Transforms an image by the given matrix. From 0b8d9d1b081e847b34fdd8de71cf8f6a77fc5f46 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 6 Nov 2018 21:04:30 +0100 Subject: [PATCH 312/381] simplify calculations by using intermediate results instead of calculating the same stuff multiple times --- .../Converters/CieXyzToHunterLabConverter.cs | 8 +++++--- .../Converters/HunterLabToCieXyzConverter.cs | 9 ++++++--- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 4 ++-- .../Quantization/FrameQuantizerBase{TPixel}.cs | 6 ++++-- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs index c27c61608d..f21235d06c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs @@ -45,9 +45,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation float ka = ComputeKa(this.HunterLabWhitePoint); float kb = ComputeKb(this.HunterLabWhitePoint); - float l = 100 * MathF.Sqrt(y / yn); - float a = ka * (((x / xn) - (y / yn)) / MathF.Sqrt(y / yn)); - float b = kb * (((y / yn) - (z / zn)) / MathF.Sqrt(y / yn)); + float yByYn = y / yn; + float sqrtYbyYn = MathF.Sqrt(yByYn); + float l = 100 * sqrtYbyYn; + float a = ka * (((x / xn) - yByYn) / sqrtYbyYn); + float b = kb * ((yByYn - (z / zn)) / sqrtYbyYn); if (float.IsNaN(a)) { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs index 783d29a557..4d6808e6c0 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs @@ -26,9 +26,12 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation float ka = ComputeKa(input.WhitePoint); float kb = ComputeKb(input.WhitePoint); - 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); + float pow = ImageMaths.Pow2(l / 100F); + float sqrtPow = MathF.Sqrt(pow); + float y = pow * yn; + + float x = (((a / ka) * sqrtPow) + pow) * xn; + float z = (((b / kb) * sqrtPow) - pow) * (-zn); return new CieXyz(x, y, z); } diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 7ae716aa05..468f619b94 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -896,9 +896,9 @@ namespace SixLabors.ImageSharp.Formats.Png 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); int shift = 8 - bits; + byte mask = (byte)(0xFF >> shift); + byte shift0 = (byte)shift; int v = 0; int resultOffset = 0; diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs index a8c6c5d7e0..3b9b046a00 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs @@ -139,8 +139,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization protected byte GetTransparentIndex() { // Transparent pixels are much more likely to be found at the end of a palette. - int index = this.paletteVector.Length - 1; - for (int i = this.paletteVector.Length - 1; i >= 0; i--) + int paletteVectorLengthMinus1 = this.paletteVector.Length - 1; + + int index = paletteVectorLengthMinus1; + for (int i = paletteVectorLengthMinus1; i >= 0; i--) { ref Vector4 candidate = ref this.paletteVector[i]; if (candidate.Equals(default)) From ea6fc641c394abe1dc57cf1217289b61919bbabe Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 14:01:41 +0100 Subject: [PATCH 313/381] inline division as it's only used in some cases (and done at most once) --- src/ImageSharp/Processing/ResizeHelper.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Processing/ResizeHelper.cs b/src/ImageSharp/Processing/ResizeHelper.cs index b9233937b1..92af89d9e8 100644 --- a/src/ImageSharp/Processing/ResizeHelper.cs +++ b/src/ImageSharp/Processing/ResizeHelper.cs @@ -337,21 +337,19 @@ namespace SixLabors.ImageSharp.Processing float percentHeight = MathF.Abs(height / (float)sourceHeight); float percentWidth = MathF.Abs(width / (float)sourceWidth); - float sourceRatio = (float)sourceHeight / sourceWidth; - // Find the shortest distance to go. int widthDiff = sourceWidth - width; int heightDiff = sourceHeight - height; if (widthDiff < heightDiff) { - destinationHeight = (int)MathF.Round(width * sourceRatio); + destinationHeight = (int)MathF.Round(width * ((float)sourceHeight / sourceWidth)); height = destinationHeight; destinationWidth = width; } else if (widthDiff > heightDiff) { - destinationWidth = (int)MathF.Round(height / sourceRatio); + destinationWidth = (int)MathF.Round(height * ((float)sourceWidth / sourceHeight)); destinationHeight = height; width = destinationWidth; } From df155496b751e8132298eb9ff72f527a865f9337 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 15:02:50 +0100 Subject: [PATCH 314/381] inline variable --- .../Processing/Processors/Text/DrawTextProcessor.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs index 487c880644..266d842bfa 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs @@ -139,10 +139,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text fistRow = -startY; } - int end = operation.Map.Height; - int maxHeight = source.Height - startY; - end = Math.Min(end, maxHeight); + int end = Math.Min(operation.Map.Height, maxHeight); for (int row = fistRow; row < end; row++) { From 74dba7a9edf22b86d0f682e999af62b26faa6a11 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 15:04:42 +0100 Subject: [PATCH 315/381] unwrap for-loop to avoid conditional check inside it is known beforehand when the if condition inside the loop will not match: only in the last iteration. Thus we can loop once less and append the last element afterwards. --- src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs index 2be5addc2f..81393342d6 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs @@ -543,15 +543,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components { var sb = new StringBuilder(); sb.Append('['); - for (int i = 0; i < Size; i++) + for (int i = 0; i < Size - 1; i++) { sb.Append(this[i]); - if (i < Size - 1) - { - sb.Append(','); - } + sb.Append(','); } + sb.Append(this[Size - 1]); + sb.Append(']'); return sb.ToString(); } From 3ebcebe99e8c1bce7f285a8c94c7b2001d00bbda Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 15:05:56 +0100 Subject: [PATCH 316/381] inline variable initialization --- src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 67f665576b..f6da9cb2ec 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -856,10 +856,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg private void ProcessStartOfScanMarker() { int selectorsCount = this.InputStream.ReadByte(); - int componentIndex = -1; for (int i = 0; i < selectorsCount; i++) { - componentIndex = -1; + int componentIndex = -1; int selector = this.InputStream.ReadByte(); for (int j = 0; j < this.Frame.ComponentIds.Length; j++) From bb360ce3568f33da0f969d0f5708a84b58fd493c Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 15:48:19 +0100 Subject: [PATCH 317/381] invert condition: always assign literal 1, substract only on special case --- src/ImageSharp/Formats/Gif/LzwEncoder.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/LzwEncoder.cs b/src/ImageSharp/Formats/Gif/LzwEncoder.cs index 34c353ec97..2d32fd23aa 100644 --- a/src/ImageSharp/Formats/Gif/LzwEncoder.cs +++ b/src/ImageSharp/Formats/Gif/LzwEncoder.cs @@ -309,10 +309,10 @@ namespace SixLabors.ImageSharp.Formats.Gif // Non-empty slot if (Unsafe.Add(ref hashTableRef, i) >= 0) { - int disp = hsizeReg - i; - if (i == 0) + int disp = 1; + if (i != 0) { - disp = 1; + disp = hsizeReg - i; } do From b6e9eb6f68b079a6f577a4ae550784453946aca2 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 15:56:38 +0100 Subject: [PATCH 318/381] multiply once and reuse --- src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index a4677ba2b7..0dcbd8fef7 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -822,11 +822,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg { for (int i = 0; i < componentCount; i++) { - this.buffer[(3 * i) + 6] = (byte)(i + 1); + int i3 = 3 * i; + this.buffer[i3 + 6] = (byte)(i + 1); // We use 4:2:0 chroma subsampling by default. - this.buffer[(3 * i) + 7] = subsamples[i]; - this.buffer[(3 * i) + 8] = chroma[i]; + this.buffer[i3 + 7] = subsamples[i]; + this.buffer[i3 + 8] = chroma[i]; } } From 34481a645a7d7d257a3e0f661ba25e49da4993b7 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 16:02:54 +0100 Subject: [PATCH 319/381] avoid local variable copy when the original is never changed --- src/ImageSharp/Formats/Png/PngScanlineProcessor.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index 3fe590ee24..420775eca9 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -190,12 +190,11 @@ namespace SixLabors.ImageSharp.Formats.Png 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); + byte alpha = Unsafe.Add(ref scanlineSpanRef, offset + bytesPerSample); rgba32.R = luminance; rgba32.G = luminance; From 0da4c45cbd79059cc499522c4a76aa7294eb2b74 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 16:03:49 +0100 Subject: [PATCH 320/381] return first matching ImageFormat when iterating over FormatDetectors --- src/ImageSharp/Image.FromBytes.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs index 07adc03ff6..34927e6e2b 100644 --- a/src/ImageSharp/Image.FromBytes.cs +++ b/src/ImageSharp/Image.FromBytes.cs @@ -198,18 +198,17 @@ namespace SixLabors.ImageSharp return null; } - IImageFormat format = default; foreach (IImageFormatDetector detector in config.ImageFormatsManager.FormatDetectors) { IImageFormat f = detector.DetectFormat(data); if (f != null) { - format = f; + return f; } } - return format; + return default; } /// From e60deb73af13c47d1054f49cdc0cc9e7664c1351 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 23:33:22 +0100 Subject: [PATCH 321/381] avoid doubled increment in for loop and multiple array indexer access --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index eb519f4214..5a6cc1260e 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -310,9 +310,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp } else { - for (int i = 0; i < cmd[0]; i++) + int max = cmd[0] + count; + byte cmd1 = cmd[1]; + + for (; count < max; count++) { - buffer[count++] = cmd[1]; + buffer[count] = cmd1; } } } From 90e4a2ff0f9693c198ca6a314548b0923bf6a959 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 14:47:17 +0100 Subject: [PATCH 322/381] simplify BoxBlurProcessor kernel initialization old code seemed to be a relict from the GaussianBlurProcessor where this pattern made sense. Here each value of the matrix is just 1.0/size as a result, and we can leverage DenseMatrix.Fill() for that. --- .../Convolution/BoxBlurProcessor.cs | 31 +------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs index 0ec62ac3d4..38dc638b90 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs @@ -66,36 +66,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution ? new DenseMatrix(size, 1) : new DenseMatrix(1, size); - float sum = 0F; - for (int i = 0; i < size; i++) - { - float x = 1; - sum += x; - if (horizontal) - { - kernel[0, i] = x; - } - else - { - kernel[i, 0] = x; - } - } - - // Normalize kernel so that the sum of all weights equals 1 - if (horizontal) - { - for (int i = 0; i < size; i++) - { - kernel[0, i] = kernel[0, i] / sum; - } - } - else - { - for (int i = 0; i < size; i++) - { - kernel[i, 0] = kernel[i, 0] / sum; - } - } + kernel.Fill(1.0F / size); return kernel; } From 2afd0d572970a1dbbf48e0707ddab23ae86ec648 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 7 Nov 2018 00:00:41 +0000 Subject: [PATCH 323/381] Cleanup TransformKernel and handle negative transform dimensions --- .../Transforms/AffineTransformProcessor.cs | 6 ++++++ .../Processors/Transforms/TransformKernelMap.cs | 15 ++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index edddab1811..f63baa95c6 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -38,6 +38,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // We want to resize the canvas here taking into account any translations. this.TargetDimensions = new Size(this.transformedRectangle.Right, this.transformedRectangle.Bottom); + + // Handle a negative translation that exceeds the original with of the image. + if (this.TargetDimensions.Width <= 0 || this.TargetDimensions.Height <= 0) + { + this.TargetDimensions = sourceSize; + } } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs index 5acc7213cb..531edbc45b 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs @@ -21,8 +21,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { private readonly Buffer2D yBuffer; private readonly Buffer2D xBuffer; - private readonly float yScale; - private readonly float xScale; private readonly int yLength; private readonly int xLength; private readonly Vector2 extents; @@ -39,12 +37,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public TransformKernelMap(Configuration configuration, Size source, Size destination, IResampler sampler) { this.sampler = sampler; - (float radius, float scale) yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height); - (float radius, float scale) xRadiusScale = this.GetSamplingRadius(source.Width, destination.Width); + float yRadius = this.GetSamplingRadius(source.Height, destination.Height); + float xRadius = this.GetSamplingRadius(source.Width, destination.Width); - this.yScale = yRadiusScale.scale; - this.xScale = xRadiusScale.scale; - this.extents = new Vector2(xRadiusScale.radius, yRadiusScale.radius); + this.extents = new Vector2(xRadius, yRadius); this.xLength = (int)MathF.Ceiling((this.extents.X * 2) + 2); this.yLength = (int)MathF.Ceiling((this.extents.Y * 2) + 2); @@ -167,7 +163,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // } } - private (float radius, float scale) GetSamplingRadius(int sourceSize, int destinationSize) + [MethodImpl(InliningOptions.ShortMethod)] + private float GetSamplingRadius(int sourceSize, int destinationSize) { float scale = (float)sourceSize / destinationSize; @@ -176,7 +173,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms scale = 1F; } - return (MathF.Ceiling(scale * this.sampler.Radius), scale); + return MathF.Ceiling(scale * this.sampler.Radius); } public void Dispose() From 321cca6e815ff0abb73d3a7b2168bfa9a670fdf3 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 7 Nov 2018 18:47:08 +0100 Subject: [PATCH 324/381] #771: change order of addition as proposed by @dlemstra added comments as explanation --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 5a6cc1260e..ef3ca24ee8 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -310,8 +310,8 @@ namespace SixLabors.ImageSharp.Formats.Bmp } else { - int max = cmd[0] + count; - byte cmd1 = cmd[1]; + int max = count + cmd[0]; // as we start at the current count in the following loop, max is count + cmd[0] + byte cmd1 = cmd[1]; // store the value to avoid the repeated indexer access inside the loop for (; count < max; count++) { From 8205216dfc07f4ea6ebafcbbbbc391c8426173e7 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 10 Nov 2018 14:20:52 +0000 Subject: [PATCH 325/381] Introduce AffineTransformBuilder --- .../Processing/AffineTransformBuilder.cs | 177 +++++++++++++ .../Transforms/AffineTransformProcessor.cs | 33 ++- .../Transforms/AffineTransformProcessorOld.cs | 239 ------------------ .../CenteredAffineTransformProcessor.cs | 38 --- .../Processors/Transforms/RotateProcessor.cs | 2 +- .../Processors/Transforms/SkewProcessor.cs | 8 +- .../Processors/Transforms/TransformHelpers.cs | 20 -- .../Transforms/TransformKernelMap.cs | 56 ++-- .../Processors/Transforms/TransformUtils.cs | 78 ++++-- .../Processing/TransformExtensions.cs | 54 +--- .../ImageSharp.Benchmarks/Samplers/Rotate.cs | 10 +- tests/ImageSharp.Benchmarks/Samplers/Skew.cs | 45 ++++ .../ImageSharp.Tests/Drawing/DrawImageTest.cs | 22 +- .../Transforms/AffineTransformTests.cs | 54 ++-- 14 files changed, 360 insertions(+), 476 deletions(-) create mode 100644 src/ImageSharp/Processing/AffineTransformBuilder.cs delete mode 100644 src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessorOld.cs delete mode 100644 src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs create mode 100644 tests/ImageSharp.Benchmarks/Samplers/Skew.cs diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs new file mode 100644 index 0000000000..e5ce1450f7 --- /dev/null +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Collections.Generic; +using System.Numerics; +using SixLabors.ImageSharp.Processing.Processors.Transforms; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing +{ + /// + /// A helper class for constructing instances for use in affine transforms. + /// + public class AffineTransformBuilder + { + private readonly List matrices = new List(); + private Rectangle rectangle; + + /// + /// Initializes a new instance of the class. + /// + /// The source image size. + public AffineTransformBuilder(Size sourceSize) => this.Size = sourceSize; + + /// + /// Initializes a new instance of the class. + /// + /// The source rectangle. + public AffineTransformBuilder(Rectangle sourceRectangle) + : this(sourceRectangle.Size) + => this.rectangle = sourceRectangle; + + /// + /// Prepends a centered rotation matrix using the given rotation in degrees. + /// + /// The amount of rotation, in degrees. + /// The . + public AffineTransformBuilder PrependRotateMatrixDegrees(float degrees) + { + this.matrices.Insert(0, TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); + return this; + } + + /// + /// Gets the source image size. + /// + internal Size Size { get; } + + /// + /// Appends a centered rotation matrix using the given rotation in degrees. + /// + /// The amount of rotation, in degrees. + /// The . + public AffineTransformBuilder AppendRotateMatrixDegrees(float degrees) + { + this.matrices.Add(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); + return this; + } + + /// + /// Prepends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public AffineTransformBuilder PrependScaleMatrix(SizeF scales) + { + this.matrices.Insert(0, Matrix3x2Extensions.CreateScale(scales)); + return this; + } + + /// + /// Appends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public AffineTransformBuilder AppendScaleMatrix(SizeF scales) + { + this.matrices.Add(Matrix3x2Extensions.CreateScale(scales)); + return this; + } + + /// + /// Prepends a centered skew matrix from the give angles in degrees. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The . + public AffineTransformBuilder PrependSkewMatrixDegrees(float degreesX, float degreesY) + { + this.matrices.Insert(0, TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); + return this; + } + + /// + /// Appends a centered skew matrix from the give angles in degrees. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The . + public AffineTransformBuilder AppendSkewMatrixDegrees(float degreesX, float degreesY) + { + this.matrices.Add(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); + return this; + } + + /// + /// Prepends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public AffineTransformBuilder PrependTranslationMatrix(PointF position) + { + this.matrices.Insert(0, Matrix3x2Extensions.CreateTranslation(position)); + return this; + } + + /// + /// Appends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public AffineTransformBuilder AppendTranslationMatrix(PointF position) + { + this.matrices.Add(Matrix3x2Extensions.CreateTranslation(position)); + return this; + } + + /// + /// Prepends a raw matrix. + /// + /// The matrix to prepend. + /// The . + public AffineTransformBuilder PrependMatrix(Matrix3x2 matrix) + { + this.matrices.Insert(0, matrix); + return this; + } + + /// + /// Appends a raw matrix. + /// + /// The matrix to append. + /// The . + public AffineTransformBuilder AppendMatrix(Matrix3x2 matrix) + { + this.matrices.Add(matrix); + return this; + } + + /// + /// Returns the combined matrix. + /// + /// The . + public Matrix3x2 BuildMatrix() + { + Matrix3x2 matrix = Matrix3x2.Identity; + + // Translate the origin matrix to cater for source rectangle offsets. + if (!this.rectangle.Equals(default)) + { + matrix *= Matrix3x2.CreateTranslation(-this.rectangle.Location); + } + + foreach (Matrix3x2 m in this.matrices) + { + matrix *= m; + } + + return matrix; + } + + /// + /// Removes all matrices from the builder. + /// + public void Clear() => this.matrices.Clear(); + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index f63baa95c6..fb42b83341 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -19,8 +19,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms internal class AffineTransformProcessor : TransformProcessorBase where TPixel : struct, IPixel { - private readonly Rectangle transformedRectangle; - /// /// Initializes a new instance of the class. /// @@ -32,18 +30,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Guard.NotNull(sampler, nameof(sampler)); this.Sampler = sampler; this.TransformMatrix = matrix; - this.transformedRectangle = TransformUtils.GetTransformedRectangle( - new Rectangle(Point.Empty, sourceSize), - matrix); - - // We want to resize the canvas here taking into account any translations. - this.TargetDimensions = new Size(this.transformedRectangle.Right, this.transformedRectangle.Bottom); - - // Handle a negative translation that exceeds the original with of the image. - if (this.TargetDimensions.Width <= 0 || this.TargetDimensions.Height <= 0) - { - this.TargetDimensions = sourceSize; - } + this.TargetDimensions = TransformUtils.GetTransformedSize(sourceSize, matrix); } /// @@ -79,10 +66,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Rectangle sourceRectangle, Configuration configuration) { + // Handle tranforms that result in output identical to the original. + if (this.TransformMatrix.Equals(Matrix3x2.Identity)) + { + // The cloned will be blank here copy all the pixel data over + source.GetPixelSpan().CopyTo(destination.GetPixelSpan()); + return; + } + int height = this.TargetDimensions.Height; int width = this.TargetDimensions.Width; - Rectangle sourceBounds = source.Bounds(); var targetBounds = new Rectangle(Point.Empty, this.TargetDimensions); // Convert from screen to world space. @@ -102,7 +96,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int x = 0; x < width; x++) { var point = Point.Transform(new Point(x, y), matrix); - if (sourceBounds.Contains(point.X, point.Y)) + if (sourceRectangle.Contains(point.X, point.Y)) { destRow[x] = source[point.X, point.Y]; } @@ -113,7 +107,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return; } - using (var kernel = new TransformKernelMap(configuration, source.Size(), destination.Size(), this.Sampler)) + var kernel = new TransformKernelMap(configuration, source.Size(), destination.Size(), this.Sampler); + try { ParallelHelper.IterateRowsWithTempBuffer( targetBounds, @@ -140,6 +135,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } }); } + finally + { + kernel.Dispose(); + } } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessorOld.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessorOld.cs deleted file mode 100644 index 5891afd9a6..0000000000 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessorOld.cs +++ /dev/null @@ -1,239 +0,0 @@ -// 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 System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -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.Transforms -{ - /// - /// Provides the base methods to perform affine transforms on an image. - /// - /// The pixel format. - internal class AffineTransformProcessorOld : InterpolatedTransformProcessorBase - where TPixel : struct, IPixel - { - /// - /// Initializes a new instance of the class. - /// - /// The transform matrix - /// The sampler to perform the transform operation. - /// The target dimensions to constrain the transformed image to. - public AffineTransformProcessorOld(Matrix3x2 matrix, IResampler sampler, Size targetDimensions) - : base(sampler) - { - this.TransformMatrix = matrix; - this.TargetDimensions = targetDimensions; - } - - /// - /// Gets the matrix used to supply the affine transform - /// - public Matrix3x2 TransformMatrix { get; } - - /// - /// Gets the target dimensions to constrain the transformed image to - /// - public Size TargetDimensions { get; } - - /// - 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.TargetDimensions, x.MetaData.DeepClone())); - - // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); - } - - /// - protected override void OnFrameApply( - ImageFrame source, - ImageFrame destination, - Rectangle sourceRectangle, - Configuration configuration) - { - int height = this.TargetDimensions.Height; - int width = this.TargetDimensions.Width; - - Rectangle sourceBounds = source.Bounds(); - var targetBounds = new Rectangle(0, 0, width, height); - - // Since could potentially be resizing the canvas we might need to re-calculate the matrix - Matrix3x2 matrix = this.GetProcessingMatrix(sourceBounds, targetBounds); - - // Convert from screen to world space. - Matrix3x2.Invert(matrix, out matrix); - - if (this.Sampler is NearestNeighborResampler) - { - ParallelHelper.IterateRows( - targetBounds, - configuration, - rows => - { - for (int y = rows.Min; y < rows.Max; 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; - } - - int maxSourceX = source.Width - 1; - int maxSourceY = source.Height - 1; - (float radius, float scale, float ratio) xRadiusScale = this.GetSamplingRadius(source.Width, destination.Width); - (float radius, float scale, float ratio) yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height); - float xScale = xRadiusScale.scale; - float yScale = yRadiusScale.scale; - var radius = new Vector2(xRadiusScale.radius, yRadiusScale.radius); - IResampler sampler = this.Sampler; - var maxSource = new Vector4(maxSourceX, maxSourceY, maxSourceX, maxSourceY); - int xLength = (int)MathF.Ceiling((radius.X * 2) + 2); - int yLength = (int)MathF.Ceiling((radius.Y * 2) + 2); - - MemoryAllocator memoryAllocator = configuration.MemoryAllocator; - - using (Buffer2D yBuffer = memoryAllocator.Allocate2D(yLength, height)) - using (Buffer2D xBuffer = memoryAllocator.Allocate2D(xLength, height)) - { - ParallelHelper.IterateRows( - targetBounds, - configuration, - rows => - { - for (int y = rows.Min; y < rows.Max; 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++) - { - // 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; - } - - // 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); - } - - // 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); - - // Values are first premultiplied to prevent darkening of edge pixels - 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 - Vector4Utils.UnPremultiply(ref sum); - dest.FromVector4(sum); - } - } - }); - } - } - - /// - /// Gets a transform matrix adjusted for final processing based upon the target image bounds. - /// - /// The source image bounds. - /// The destination image bounds. - /// - /// The . - /// - protected virtual Matrix3x2 GetProcessingMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle) - => this.TransformMatrix; - } -} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs deleted file mode 100644 index 82614dc8c2..0000000000 --- a/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Processing.Processors.Transforms -{ - /// - /// A base class that provides methods to allow the automatic centering of affine transforms - /// - /// The pixel format. - internal abstract class CenteredAffineTransformProcessor : AffineTransformProcessorOld - where TPixel : struct, IPixel - { - /// - /// Initializes a new instance of the class. - /// - /// The transform matrix - /// The sampler to perform the transform operation. - /// The source image size - protected CenteredAffineTransformProcessor(Matrix3x2 matrix, IResampler sampler, Size sourceSize) - : base(matrix, sampler, GetTransformedDimensions(sourceSize, matrix)) - { - } - - /// - protected override Matrix3x2 GetProcessingMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle) - => TransformHelpers.GetCenteredTransformMatrix(sourceRectangle, destinationRectangle, this.TransformMatrix); - - private static Size GetTransformedDimensions(Size sourceDimensions, Matrix3x2 matrix) - { - var sourceRectangle = new Rectangle(0, 0, sourceDimensions.Width, sourceDimensions.Height); - return TransformHelpers.GetTransformedBoundingRectangle(sourceRectangle, matrix).Size; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs index cbf82cc9b0..57cca4bf9e 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The source image size public RotateProcessor(float degrees, IResampler sampler, Size sourceSize) : base( - TransformUtils.CreateCenteredRotationMatrixDegrees(degrees, sourceSize), + TransformUtils.CreateRotationMatrixDegrees(degrees, sourceSize), sampler, sourceSize) => this.Degrees = degrees; diff --git a/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs index a0cfa63794..4a006a9dfe 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Transforms @@ -11,7 +10,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// Provides methods that allow the skewing of images. /// /// The pixel format. - internal class SkewProcessor : CenteredAffineTransformProcessor + internal class SkewProcessor : AffineTransformProcessor where TPixel : struct, IPixel { /// @@ -33,7 +32,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The sampler to perform the skew operation. /// The source image size public SkewProcessor(float degreesX, float degreesY, IResampler sampler, Size sourceSize) - : base(Matrix3x2Extensions.CreateSkewDegrees(degreesX, degreesY, PointF.Empty), sampler, sourceSize) + : base( + TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, sourceSize), + sampler, + sourceSize) { this.DegreesX = degreesX; this.DegreesY = degreesY; diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformHelpers.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformHelpers.cs index b22fa64cfd..2e85f6c2cc 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformHelpers.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformHelpers.cs @@ -102,26 +102,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return centered; } - /// - /// Returns the bounding rectangle relative to the source for the given transformation matrix. - /// - /// The source rectangle. - /// The transformation matrix. - /// - /// The . - /// - public static Rectangle GetTransformedBoundingRectangle(Rectangle rectangle, Matrix3x2 matrix) - { - // Calculate the position of the four corners in world space by applying - // The world matrix to the four corners in object space (0, 0, width, height) - var tl = Vector2.Transform(Vector2.Zero, matrix); - var tr = Vector2.Transform(new Vector2(rectangle.Width, 0), matrix); - var bl = Vector2.Transform(new Vector2(0, rectangle.Height), matrix); - var br = Vector2.Transform(new Vector2(rectangle.Width, rectangle.Height), matrix); - - return GetBoundingRectangle(tl, tr, bl, br); - } - /// /// Returns the bounding rectangle relative to the source for the given transformation matrix. /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs index 531edbc45b..573120888f 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs @@ -9,20 +9,15 @@ using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; -// TODO: It would be great if we could somehow optimize this to calculate the weights once. -// currently we cannot do that as we are calulating the weight of the transformed point dimension -// not the point in the original image. namespace SixLabors.ImageSharp.Processing.Processors.Transforms { /// - /// Contains the methods required to calculate kernel sampling weights on-the-fly. + /// Contains the methods required to calculate transform kernel convolution. /// internal class TransformKernelMap : IDisposable { private readonly Buffer2D yBuffer; private readonly Buffer2D xBuffer; - private readonly int yLength; - private readonly int xLength; private readonly Vector2 extents; private Vector4 maxSourceExtents; private readonly IResampler sampler; @@ -41,12 +36,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms float xRadius = this.GetSamplingRadius(source.Width, destination.Width); this.extents = new Vector2(xRadius, yRadius); - this.xLength = (int)MathF.Ceiling((this.extents.X * 2) + 2); - this.yLength = (int)MathF.Ceiling((this.extents.Y * 2) + 2); + int xLength = (int)MathF.Ceiling((this.extents.X * 2) + 2); + int yLength = (int)MathF.Ceiling((this.extents.Y * 2) + 2); - // We use 2D buffers so that we can access the weight spans in parallel. - this.yBuffer = configuration.MemoryAllocator.Allocate2D(this.yLength, destination.Height); - this.xBuffer = configuration.MemoryAllocator.Allocate2D(this.xLength, destination.Height); + // We use 2D buffers so that we can access the weight spans per row in parallel. + this.yBuffer = configuration.MemoryAllocator.Allocate2D(yLength, destination.Height); + this.xBuffer = configuration.MemoryAllocator.Allocate2D(xLength, destination.Height); int maxX = source.Width - 1; int maxY = source.Height - 1; @@ -82,42 +77,34 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Vector2 minXY = transformedPoint - this.extents; Vector2 maxXY = transformedPoint + this.extents; - // minX, minY, maxX, maxY + // left, top, right, bottom var extents = new Vector4( MathF.Ceiling(minXY.X - .5F), MathF.Ceiling(minXY.Y - .5F), MathF.Floor(maxXY.X + .5F), MathF.Floor(maxXY.Y + .5F)); + extents = Vector4.Clamp(extents, Vector4.Zero, this.maxSourceExtents); + int left = (int)extents.X; int top = (int)extents.Y; int right = (int)extents.Z; int bottom = (int)extents.W; - extents = Vector4.Clamp(extents, Vector4.Zero, this.maxSourceExtents); - - int minX = (int)extents.X; - int minY = (int)extents.Y; - int maxX = (int)extents.Z; - int maxY = (int)extents.W; - - if (minX == maxX || minY == maxY) + if (left == right || top == bottom) { return; } - // TODO: Get Anton to use his superior brain on this one. - // It looks to me like we're calculating the same weights over and over again - // since min(X+Y) and max(X+Y) are the same distance apart. - this.CalculateWeights(minY, maxY, maxY - minY, transformedPoint.Y, ref ySpanRef); - this.CalculateWeights(minX, maxX, maxX - minX, transformedPoint.X, ref xSpanRef); + this.CalculateWeights(top, bottom, transformedPoint.Y, ref ySpanRef); + this.CalculateWeights(left, right, transformedPoint.X, ref xSpanRef); Vector4 sum = Vector4.Zero; - for (int kernelY = 0, y = minY; y <= maxY; y++, kernelY++) + for (int kernelY = 0, y = top; y <= bottom; y++, kernelY++) { float yWeight = Unsafe.Add(ref ySpanRef, kernelY); - for (int kernelX = 0, x = minX; x <= maxX; x++, kernelX++) + for (int kernelX = 0, x = left; x <= right; x++, kernelX++) { float xWeight = Unsafe.Add(ref xSpanRef, kernelX); @@ -138,29 +125,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// The minimum sampling offset /// The maximum sampling offset - /// The length of the weights collection /// The transformed point dimension /// The reference to the collection of weights [MethodImpl(InliningOptions.ShortMethod)] - private void CalculateWeights(int min, int max, int length, float point, ref float weightsRef) + private void CalculateWeights(int min, int max, float point, ref float weightsRef) { float sum = 0; for (int x = 0, i = min; i <= max; i++, x++) { float weight = this.sampler.GetValue(i - point); sum += weight; - Unsafe.Add(ref weightsRef, x) = this.sampler.GetValue(i - point); + Unsafe.Add(ref weightsRef, x) = weight; } - - // TODO: Do we need this? Check what happens when we scale an image down. - // if (sum > 0) - // { - // for (int i = 0; i < length; i++) - // { - // ref float wRef = ref Unsafe.Add(ref weightsRef, i); - // wRef /= sum; - // } - // } } [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs index 7d03502499..10cf49c34b 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// Contains utility methods for working with transforms. /// - public static class TransformUtils + internal static class TransformUtils { /// /// Creates a centered rotation matrix using the given rotation in degrees and the source size. @@ -18,43 +18,33 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The amount of rotation, in degrees. /// The source image size. /// The . - public static Matrix3x2 CreateCenteredRotationMatrixDegrees(float degrees, Size size) + public static Matrix3x2 CreateRotationMatrixDegrees(float degrees, Size size) => CreateCenteredTransformMatrix( new Rectangle(Point.Empty, size), Matrix3x2Extensions.CreateRotationDegrees(degrees, PointF.Empty)); /// - /// Gets the centered transform matrix based upon the source and destination rectangles. + /// Creates a centered skew matrix from the give angles in degrees and the source size. /// - /// The source image bounds. - /// The transformation matrix. - /// The - public static Matrix3x2 CreateCenteredTransformMatrix(Rectangle sourceRectangle, Matrix3x2 matrix) - { - Rectangle destinationRectangle = GetTransformedBoundingRectangle(sourceRectangle, matrix); - - // We invert the matrix to handle the transformation from screen to world space. - // This ensures scaling matrices are correct. - Matrix3x2.Invert(matrix, out Matrix3x2 inverted); - - var translationToTargetCenter = Matrix3x2.CreateTranslation(new Vector2(-destinationRectangle.Width, -destinationRectangle.Height) * .5F); - var translateToSourceCenter = Matrix3x2.CreateTranslation(new Vector2(sourceRectangle.Width, sourceRectangle.Height) * .5F); - - // Translate back to world space. - Matrix3x2.Invert(translationToTargetCenter * inverted * translateToSourceCenter, out Matrix3x2 centered); - - return centered; - } + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The source image size. + /// The . + public static Matrix3x2 CreateSkewMatrixDegrees(float degreesX, float degreesY, Size size) + => CreateCenteredTransformMatrix( + new Rectangle(Point.Empty, size), + Matrix3x2Extensions.CreateSkewDegrees(degreesX, degreesY, PointF.Empty)); /// /// Gets the centered transform matrix based upon the source and destination rectangles. /// /// The source image bounds. - /// The destination image bounds. /// The transformation matrix. /// The - public static Matrix3x2 GetCenteredTransformMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle, Matrix3x2 matrix) + public static Matrix3x2 CreateCenteredTransformMatrix(Rectangle sourceRectangle, Matrix3x2 matrix) { + Rectangle destinationRectangle = GetTransformedBoundingRectangle(sourceRectangle, matrix); + // We invert the matrix to handle the transformation from screen to world space. // This ensures scaling matrices are correct. Matrix3x2.Invert(matrix, out Matrix3x2 inverted); @@ -79,8 +69,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public static Rectangle GetTransformedBoundingRectangle(Rectangle rectangle, Matrix3x2 matrix) { Rectangle transformed = GetTransformedRectangle(rectangle, matrix); - - // TODO: Check this. return new Rectangle(0, 0, transformed.Width, transformed.Height); } @@ -107,6 +95,44 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return GetBoundingRectangle(tl, tr, bl, br); } + /// + /// Returns the size relative to the source for the given transformation matrix. + /// + /// The source size. + /// The transformation matrix. + /// + /// The . + /// + public static Size GetTransformedSize(Size size, Matrix3x2 matrix) + { + Guard.IsTrue(size.Width > 0 && size.Height > 0, nameof(size), "Source size dimensions cannot be 0!"); + + if (matrix.Equals(default) || matrix.Equals(Matrix3x2.Identity)) + { + return size; + } + + Rectangle rectangle = GetTransformedRectangle(new Rectangle(Point.Empty, size), matrix); + + // We want to resize the canvas here taking into account any translations. + int height = rectangle.Top < 0 ? rectangle.Bottom : Math.Max(rectangle.Height, rectangle.Bottom); + int width = rectangle.Left < 0 ? rectangle.Right : Math.Max(rectangle.Width, rectangle.Right); + + // If location in either direction is translated to a negative value equal to or exceeding the + // dimensions in eith direction we need to reassign the dimension. + if (height <= 0) + { + height = rectangle.Height; + } + + if (width <= 0) + { + width = rectangle.Width; + } + + return new Size(width, height); + } + private static Rectangle GetBoundingRectangle(Vector2 tl, Vector2 tr, Vector2 bl, Vector2 br) { // Find the minimum and maximum "corners" based on the given vectors diff --git a/src/ImageSharp/Processing/TransformExtensions.cs b/src/ImageSharp/Processing/TransformExtensions.cs index 3f24969a3d..4cbd1b041f 100644 --- a/src/ImageSharp/Processing/TransformExtensions.cs +++ b/src/ImageSharp/Processing/TransformExtensions.cs @@ -18,65 +18,23 @@ namespace SixLabors.ImageSharp.Processing /// /// The pixel format. /// The image to transform. - /// The transformation matrix. + /// The affine transform builder. /// The - public static IImageProcessingContext Transform(this IImageProcessingContext source, Matrix3x2 matrix) + public static IImageProcessingContext Transform(this IImageProcessingContext source, AffineTransformBuilder builder) where TPixel : struct, IPixel - => Transform(source, matrix, KnownResamplers.Bicubic); + => Transform(source, builder, KnownResamplers.Bicubic); /// /// Transforms an image by the given matrix using the specified sampling algorithm. /// /// The pixel format. /// The image to transform. - /// The transformation matrix. - /// The to perform the resampling. - /// The - public static IImageProcessingContext Transform(this IImageProcessingContext source, Matrix3x2 matrix, IResampler sampler) - where TPixel : struct, IPixel - => source.ApplyProcessor(new AffineTransformProcessorOld(matrix, sampler, source.GetCurrentSize())); - - /// - /// Transforms an image by the given matrix using the specified sampling algorithm - /// and a rectangle defining the transform origin in the source image and the size of the result image. - /// - /// The pixel format. - /// The image to transform. - /// The transformation matrix. - /// The to perform the resampling. - /// - /// The rectangle defining the transform origin in the source image, and the size of the result image. - /// - /// The - public static IImageProcessingContext Transform( - this IImageProcessingContext source, - Matrix3x2 matrix, - IResampler sampler, - Rectangle rectangle) - where TPixel : struct, IPixel - { - var t = Matrix3x2.CreateTranslation(-rectangle.Location); - Matrix3x2 combinedMatrix = t * matrix; - return source.ApplyProcessor(new AffineTransformProcessorOld(combinedMatrix, sampler, rectangle.Size)); - } - - /// - /// Transforms an image by the given matrix using the specified sampling algorithm, - /// cropping or extending the image according to . - /// - /// The pixel format. - /// The image to transform. - /// The transformation matrix. + /// The affine transform builder. /// The to perform the resampling. - /// The size of the destination image. /// The - public static IImageProcessingContext Transform( - this IImageProcessingContext source, - Matrix3x2 matrix, - IResampler sampler, - Size destinationSize) + public static IImageProcessingContext Transform(this IImageProcessingContext source, AffineTransformBuilder builder, IResampler sampler) where TPixel : struct, IPixel - => source.ApplyProcessor(new AffineTransformProcessorOld(matrix, sampler, destinationSize)); + => source.ApplyProcessor(new AffineTransformProcessor(builder.BuildMatrix(), sampler, builder.Size)); /// /// Transforms an image by the given matrix. diff --git a/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs b/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs index c1456f9d77..f898576af0 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Samplers } } -// Nov 4 2018 +// Nov 7 2018 //BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17763 //Intel Core i7-6600U CPU 2.60GHz(Skylake), 1 CPU, 4 logical and 2 physical cores //.NET Core SDK = 2.1.403 @@ -36,4 +36,10 @@ namespace SixLabors.ImageSharp.Benchmarks.Samplers // Method | Runtime | Mean | Error | StdDev | Allocated | //--------- |-------- |---------:|----------:|----------:|----------:| // DoRotate | Clr | 85.19 ms | 13.379 ms | 0.7560 ms | 6 KB | -// DoRotate | Core | 53.51 ms | 9.512 ms | 0.5375 ms | 4.29 KB | \ No newline at end of file +// DoRotate | Core | 53.51 ms | 9.512 ms | 0.5375 ms | 4.29 KB | + +// #### AFTER ####: +//Method | Runtime | Mean | Error | StdDev | Allocated | +//--------- |-------- |---------:|---------:|---------:|----------:| +// DoRotate | Clr | 77.08 ms | 23.97 ms | 1.354 ms | 6 KB | +// DoRotate | Core | 40.36 ms | 47.43 ms | 2.680 ms | 4.36 KB | \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Samplers/Skew.cs b/tests/ImageSharp.Benchmarks/Samplers/Skew.cs new file mode 100644 index 0000000000..84819750af --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Samplers/Skew.cs @@ -0,0 +1,45 @@ +using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Benchmarks.Samplers +{ + [Config(typeof(Config.ShortClr))] + public class Skew + { + [Benchmark] + public Size DoSkew() + { + using (var image = new Image(Configuration.Default, 400, 400, Rgba32.BlanchedAlmond)) + { + image.Mutate(x => x.Skew(20, 10)); + + return image.Size(); + } + } + } +} + +// Nov 7 2018 +//BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17763 +//Intel Core i7-6600U CPU 2.60GHz(Skylake), 1 CPU, 4 logical and 2 physical cores +//.NET Core SDK = 2.1.403 + +// [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT +// Job-KKDIMW : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 +// Job-IUZRFA : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + +//LaunchCount=1 TargetCount=3 WarmupCount=3 + +// #### BEFORE ####: +//Method | Runtime | Mean | Error | StdDev | Allocated | +//------- |-------- |---------:|---------:|----------:|----------:| +// DoSkew | Clr | 78.14 ms | 8.383 ms | 0.4736 ms | 6 KB | +// DoSkew | Core | 44.22 ms | 4.109 ms | 0.2322 ms | 4.28 KB | + +// #### AFTER ####: +//Method | Runtime | Mean | Error | StdDev | Allocated | +//------- |-------- |---------:|----------:|----------:|----------:| +// DoSkew | Clr | 71.63 ms | 25.589 ms | 1.4458 ms | 6 KB | +// DoSkew | Core | 38.99 ms | 8.640 ms | 0.4882 ms | 4.36 KB | \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs index 496692d969..564318e5e3 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs @@ -2,10 +2,8 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Numerics; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; -using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using SixLabors.Primitives; using Xunit; @@ -75,21 +73,15 @@ namespace SixLabors.ImageSharp.Tests using (Image image = provider.GetImage()) using (var blend = Image.Load(TestFile.Create(TestImages.Bmp.Car).Bytes)) { - Matrix3x2 rotate = Matrix3x2Extensions.CreateRotationDegrees(45F); - Matrix3x2 scale = Matrix3x2Extensions.CreateScale(new SizeF(.25F, .25F)); - Matrix3x2 matrix = rotate * scale; + AffineTransformBuilder builder = new AffineTransformBuilder(blend.Size()) + .AppendRotateMatrixDegrees(45F) + .AppendScaleMatrix(new SizeF(.25F, .25F)) + .AppendTranslationMatrix(new PointF(10, 10)); - // Lets center the matrix so we can tell whether any cut-off issues we may have belong to the drawing processor - Rectangle srcBounds = blend.Bounds(); - Rectangle destBounds = TransformHelpers.GetTransformedBoundingRectangle(srcBounds, matrix); - Matrix3x2 centeredMatrix = TransformHelpers.GetCenteredTransformMatrix(srcBounds, destBounds, matrix); - - // We pass a new rectangle here based on the dest bounds since we've offset the matrix - blend.Mutate(x => x.Transform( - centeredMatrix, - KnownResamplers.Bicubic, - new Rectangle(0, 0, destBounds.Width, destBounds.Height))); + // Apply a background color so we can see the translation. + blend.Mutate(x => x.Transform(builder).BackgroundColor(NamedColors.HotPink)); + // Lets center the matrix so we can tell whether any cut-off issues we may have belong to the drawing processor var position = new Point((image.Width - blend.Width) / 2, (image.Height - blend.Height) / 2); image.Mutate(x => x.DrawImage(blend, position, mode, .75F)); image.DebugSave(provider, new[] { "Transformed" }); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index ae572498a4..32280d48cd 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -78,15 +78,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms IResampler resampler = GetResampler(resamplerName); using (Image image = provider.GetImage()) { - var rotate = Matrix3x2.CreateRotation((float)Math.PI / 4F, new Vector2(5 / 2F, 5 / 2F)); - var translate = Matrix3x2.CreateTranslation((7 - 5) / 2F, (7 - 5) / 2F); + AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) + .AppendRotateMatrixDegrees((float)Math.PI / 4F); - Rectangle sourceRectangle = image.Bounds(); - Matrix3x2 matrix = rotate * translate; - - Rectangle destRectangle = TransformHelpers.GetTransformedBoundingRectangle(sourceRectangle, matrix); - - image.Mutate(c => c.Transform(matrix, resampler, destRectangle)); + image.Mutate(c => c.Transform(builder, resampler)); image.DebugSave(provider, resamplerName); VerifyAllPixelsAreWhiteOrTransparent(image); @@ -104,14 +99,15 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { using (Image image = provider.GetImage()) { - Matrix3x2 rotate = Matrix3x2Extensions.CreateRotationDegrees(angleDeg); - var translate = Matrix3x2.CreateTranslation(tx, ty); - var scale = Matrix3x2.CreateScale(sx, sy); - Matrix3x2 m = rotate * scale * translate; + image.DebugSave(provider, $"_original"); + AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) + .AppendRotateMatrixDegrees(angleDeg) + .AppendScaleMatrix(new SizeF(sx, sy)) + .AppendTranslationMatrix(new PointF(tx, ty)); - this.PrintMatrix(m); + this.PrintMatrix(builder.BuildMatrix()); - image.Mutate(i => i.Transform(m, KnownResamplers.Bicubic)); + image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic)); FormattableString testOutputDetails = $"R({angleDeg})_S({sx},{sy})_T({tx},{ty})"; image.DebugSave(provider, testOutputDetails); @@ -126,9 +122,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { using (Image image = provider.GetImage()) { - Matrix3x2 m = this.MakeManuallyCenteredMatrix(angleDeg, s, image); + AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) + .AppendRotateMatrixDegrees(angleDeg) + .AppendScaleMatrix(new SizeF(s, s)); - image.Mutate(i => i.Transform(m, KnownResamplers.Bicubic)); + image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic)); FormattableString testOutputDetails = $"R({angleDeg})_S({s})"; image.DebugSave(provider, testOutputDetails); @@ -155,13 +153,15 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms public void Transform_FromSourceRectangle1(TestImageProvider provider) where TPixel : struct, IPixel { - var rectangle = new Rectangle(48, 0, 96, 36); + var rectangle = new Rectangle(48, 0, 48, 24); using (Image image = provider.GetImage()) { - var m = Matrix3x2.CreateScale(2.0F, 1.5F); + image.DebugSave(provider, $"_original"); + AffineTransformBuilder builder = new AffineTransformBuilder(rectangle) + .AppendScaleMatrix(new SizeF(2, 1.5F)); - image.Mutate(i => i.Transform(m, KnownResamplers.Spline, rectangle)); + image.Mutate(i => i.Transform(builder, KnownResamplers.Spline)); image.DebugSave(provider); image.CompareToReferenceOutput(ValidatorComparer, provider); @@ -173,13 +173,14 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms public void Transform_FromSourceRectangle2(TestImageProvider provider) where TPixel : struct, IPixel { - var rectangle = new Rectangle(0, 24, 48, 48); + var rectangle = new Rectangle(0, 24, 48, 24); using (Image image = provider.GetImage()) { - var m = Matrix3x2.CreateScale(1.0F, 2.0F); + AffineTransformBuilder builder = new AffineTransformBuilder(rectangle) + .AppendScaleMatrix(new SizeF(1F, 2F)); - image.Mutate(i => i.Transform(m, KnownResamplers.Spline, rectangle)); + image.Mutate(i => i.Transform(builder, KnownResamplers.Spline)); image.DebugSave(provider); image.CompareToReferenceOutput(ValidatorComparer, provider); @@ -194,12 +195,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms IResampler sampler = GetResampler(resamplerName); using (Image image = provider.GetImage()) { - Matrix3x2 m = this.MakeManuallyCenteredMatrix(50, 0.6f, image); + AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) + .AppendRotateMatrixDegrees(50) + .AppendScaleMatrix(new SizeF(.6F, .6F)); - image.Mutate(i => - { - i.Transform(m, sampler); - }); + image.Mutate(i => i.Transform(builder, sampler)); image.DebugSave(provider, resamplerName); image.CompareToReferenceOutput(ValidatorComparer, provider, resamplerName); From 0daa647b69e1a995429bb575b54dcd8dc8a19440 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 14:38:33 +0100 Subject: [PATCH 326/381] fix typo in KirschKernels class name --- .../{KirshKernels.cs => KirschKernels.cs} | 4 ++-- .../Processors/Convolution/KirschProcessor.cs | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) rename src/ImageSharp/Processing/Processors/Convolution/{KirshKernels.cs => KirschKernels.cs} (96%) diff --git a/src/ImageSharp/Processing/Processors/Convolution/KirshKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/KirschKernels.cs similarity index 96% rename from src/ImageSharp/Processing/Processors/Convolution/KirshKernels.cs rename to src/ImageSharp/Processing/Processors/Convolution/KirschKernels.cs index d315875089..86232e306a 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/KirshKernels.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/KirschKernels.cs @@ -6,9 +6,9 @@ using SixLabors.ImageSharp.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Convolution { /// - /// Contains the eight matrices used for Kirsh edge detection + /// Contains the eight matrices used for Kirsch edge detection /// - internal static class KirshKernels + internal static class KirschKernels { /// /// Gets the North gradient operator diff --git a/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs index 46cf00c226..c3188676f3 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs @@ -23,27 +23,27 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution } /// - public override DenseMatrix North => KirshKernels.KirschNorth; + public override DenseMatrix North => KirschKernels.KirschNorth; /// - public override DenseMatrix NorthWest => KirshKernels.KirschNorthWest; + public override DenseMatrix NorthWest => KirschKernels.KirschNorthWest; /// - public override DenseMatrix West => KirshKernels.KirschWest; + public override DenseMatrix West => KirschKernels.KirschWest; /// - public override DenseMatrix SouthWest => KirshKernels.KirschSouthWest; + public override DenseMatrix SouthWest => KirschKernels.KirschSouthWest; /// - public override DenseMatrix South => KirshKernels.KirschSouth; + public override DenseMatrix South => KirschKernels.KirschSouth; /// - public override DenseMatrix SouthEast => KirshKernels.KirschSouthEast; + public override DenseMatrix SouthEast => KirschKernels.KirschSouthEast; /// - public override DenseMatrix East => KirshKernels.KirschEast; + public override DenseMatrix East => KirschKernels.KirschEast; /// - public override DenseMatrix NorthEast => KirshKernels.KirschNorthEast; + public override DenseMatrix NorthEast => KirschKernels.KirschNorthEast; } } \ No newline at end of file From b196a0897546115a583b129ca99e845a0e8c2265 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 15:13:24 +0100 Subject: [PATCH 327/381] fix typo in local variable name --- .../Profiles/ICC/DataReader/IccDataReader.Curves.cs | 8 ++++---- .../ICC/DataReader/IccDataReader.TagDataEntry.cs | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Curves.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Curves.cs index ee91ad7a18..b27083dc49 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Curves.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Curves.cs @@ -41,10 +41,10 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc public IccResponseCurve ReadResponseCurve(int channelCount) { var type = (IccCurveMeasurementEncodings)this.ReadUInt32(); - uint[] measurment = new uint[channelCount]; + uint[] measurement = new uint[channelCount]; for (int i = 0; i < channelCount; i++) { - measurment[i] = this.ReadUInt32(); + measurement[i] = this.ReadUInt32(); } Vector3[] xyzValues = new Vector3[channelCount]; @@ -56,8 +56,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc IccResponseNumber[][] response = new IccResponseNumber[channelCount][]; for (int i = 0; i < channelCount; i++) { - response[i] = new IccResponseNumber[measurment[i]]; - for (uint j = 0; j < measurment[i]; j++) + response[i] = new IccResponseNumber[measurement[i]]; + for (uint j = 0; j < measurement[i]; j++) { response[i][j] = this.ReadResponseNumber(); } diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs index e41d9b3b8c..c572b7f210 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs @@ -628,16 +628,16 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc { int start = this.currentIndex - 8; // 8 is the tag header size ushort channelCount = this.ReadUInt16(); - ushort measurmentCount = this.ReadUInt16(); + ushort measurementCount = this.ReadUInt16(); - uint[] offset = new uint[measurmentCount]; - for (int i = 0; i < measurmentCount; i++) + uint[] offset = new uint[measurementCount]; + for (int i = 0; i < measurementCount; i++) { offset[i] = this.ReadUInt32(); } - var curves = new IccResponseCurve[measurmentCount]; - for (int i = 0; i < measurmentCount; i++) + var curves = new IccResponseCurve[measurementCount]; + for (int i = 0; i < measurementCount; i++) { this.currentIndex = (int)(start + offset[i]); curves[i] = this.ReadResponseCurve(channelCount); From 5589bd3e39007710b40d4f380690003a81209485 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 10 Nov 2018 21:14:30 +0000 Subject: [PATCH 328/381] Introduce ProjectiveTransformBuilder --- .../Processing/AffineTransformBuilder.cs | 10 +- .../Transforms/AffineTransformProcessor.cs | 6 +- .../CenteredProjectiveTransformProcessor.cs | 40 ---- .../InterpolatedTransformProcessorBase.cs | 116 ----------- .../ProjectiveTransformProcessor.cs | 197 +++++------------- .../Processors/Transforms/TransformHelpers.cs | 138 ------------ .../Transforms/TransformProcessorBase.cs | 2 +- .../Transforms/TransformProcessorHelpers.cs | 58 ++++++ .../Processors/Transforms/TransformUtils.cs | 162 ++++++++++++++ .../Processing/ProjectiveTransformBuilder.cs | 113 ++++++++++ .../Processing/ProjectiveTransformHelper.cs | 166 --------------- src/ImageSharp/Processing/TaperCorner.cs | 26 +++ src/ImageSharp/Processing/TaperSide.cs | 31 +++ .../Processing/TransformExtensions.cs | 40 +--- .../Transforms/AffineTransformTests.cs | 2 +- .../Transforms/ProjectiveTransformTests.cs | 27 +-- .../Transforms/TransformsHelpersTest.cs | 2 +- 17 files changed, 475 insertions(+), 661 deletions(-) delete mode 100644 src/ImageSharp/Processing/Processors/Transforms/CenteredProjectiveTransformProcessor.cs delete mode 100644 src/ImageSharp/Processing/Processors/Transforms/InterpolatedTransformProcessorBase.cs delete mode 100644 src/ImageSharp/Processing/Processors/Transforms/TransformHelpers.cs create mode 100644 src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs create mode 100644 src/ImageSharp/Processing/ProjectiveTransformBuilder.cs delete mode 100644 src/ImageSharp/Processing/ProjectiveTransformHelper.cs create mode 100644 src/ImageSharp/Processing/TaperCorner.cs create mode 100644 src/ImageSharp/Processing/TaperSide.cs diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index e5ce1450f7..ff44915b14 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -30,6 +30,11 @@ namespace SixLabors.ImageSharp.Processing : this(sourceRectangle.Size) => this.rectangle = sourceRectangle; + /// + /// Gets the source image size. + /// + internal Size Size { get; } + /// /// Prepends a centered rotation matrix using the given rotation in degrees. /// @@ -41,11 +46,6 @@ namespace SixLabors.ImageSharp.Processing return this; } - /// - /// Gets the source image size. - /// - internal Size Size { get; } - /// /// Appends a centered rotation matrix using the given rotation in degrees. /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index fb42b83341..2370adb862 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -22,9 +22,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// Initializes a new instance of the class. /// - /// The transform matrix + /// The transform matrix. /// The sampler to perform the transform operation. - /// The source image size + /// The source image size. public AffineTransformProcessor(Matrix3x2 matrix, IResampler sampler, Size sourceSize) { Guard.NotNull(sampler, nameof(sampler)); @@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Configuration configuration) { // Handle tranforms that result in output identical to the original. - if (this.TransformMatrix.Equals(Matrix3x2.Identity)) + if (this.TransformMatrix.Equals(default) || this.TransformMatrix.Equals(Matrix3x2.Identity)) { // The cloned will be blank here copy all the pixel data over source.GetPixelSpan().CopyTo(destination.GetPixelSpan()); diff --git a/src/ImageSharp/Processing/Processors/Transforms/CenteredProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CenteredProjectiveTransformProcessor.cs deleted file mode 100644 index 962b9e4c9d..0000000000 --- a/src/ImageSharp/Processing/Processors/Transforms/CenteredProjectiveTransformProcessor.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Processing.Processors.Transforms -{ - /// - /// A base class that provides methods to allow the automatic centering of non-affine transforms - /// - /// The pixel format. - internal abstract class CenteredProjectiveTransformProcessor : ProjectiveTransformProcessor - where TPixel : struct, IPixel - { - /// - /// Initializes a new instance of the class. - /// - /// The transform matrix - /// The sampler to perform the transform operation. - /// The source image size - protected CenteredProjectiveTransformProcessor(Matrix4x4 matrix, IResampler sampler, Size sourceSize) - : base(matrix, sampler, GetTransformedDimensions(sourceSize, matrix)) - { - } - - /// - protected override Matrix4x4 GetProcessingMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle) - { - return TransformHelpers.GetCenteredTransformMatrix(sourceRectangle, destinationRectangle, this.TransformMatrix); - } - - private static Size GetTransformedDimensions(Size sourceDimensions, Matrix4x4 matrix) - { - var sourceRectangle = new Rectangle(0, 0, sourceDimensions.Width, sourceDimensions.Height); - return TransformHelpers.GetTransformedBoundingRectangle(sourceRectangle, matrix).Size; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/InterpolatedTransformProcessorBase.cs b/src/ImageSharp/Processing/Processors/Transforms/InterpolatedTransformProcessorBase.cs deleted file mode 100644 index 4737a4102c..0000000000 --- a/src/ImageSharp/Processing/Processors/Transforms/InterpolatedTransformProcessorBase.cs +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp.Processing.Processors.Transforms -{ - /// - /// The base class for performing interpolated affine and non-affine transforms. - /// - /// The pixel format. - internal abstract class InterpolatedTransformProcessorBase : TransformProcessorBase - where TPixel : struct, IPixel - { - /// - /// Initializes a new instance of the class. - /// - /// The sampler to perform the transform operation. - protected InterpolatedTransformProcessorBase(IResampler sampler) - { - Guard.NotNull(sampler, nameof(sampler)); - this.Sampler = sampler; - } - - /// - /// Gets the sampler to perform interpolation of the transform operation. - /// - public IResampler Sampler { get; } - - /// - /// Calculated the weights for the given point. - /// This method uses more samples than the upscaled version to ensure edge pixels are correctly rendered. - /// Additionally the weights are normalized. - /// - /// The minimum sampling offset - /// The maximum sampling offset - /// The minimum source bounds - /// The maximum source bounds - /// The transformed point dimension - /// The sampler - /// The transformed image scale relative to the source - /// The reference to the collection of weights - /// The length of the weights collection - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected static void CalculateWeightsDown(int min, int max, int sourceMin, int sourceMax, float point, IResampler sampler, float scale, ref float weightsRef, int length) - { - float sum = 0; - - // Downsampling weights requires more edge sampling plus normalization of the weights - for (int x = 0, i = min; i <= max; i++, x++) - { - int index = i; - if (index < sourceMin) - { - index = sourceMin; - } - - if (index > sourceMax) - { - index = sourceMax; - } - - float weight = sampler.GetValue((index - point) / scale); - sum += weight; - Unsafe.Add(ref weightsRef, x) = weight; - } - - if (sum > 0) - { - for (int i = 0; i < length; i++) - { - ref float wRef = ref Unsafe.Add(ref weightsRef, i); - wRef /= sum; - } - } - } - - /// - /// Calculated the weights for the given point. - /// - /// The minimum source bounds - /// The maximum source bounds - /// The transformed point dimension - /// The sampler - /// The reference to the collection of weights - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected static void CalculateWeightsScaleUp(int sourceMin, int sourceMax, float point, IResampler sampler, ref float weightsRef) - { - for (int x = 0, i = sourceMin; i <= sourceMax; i++, x++) - { - Unsafe.Add(ref weightsRef, x) = sampler.GetValue(i - point); - } - } - - /// - /// Calculates the sampling radius for the current sampler - /// - /// The source dimension size - /// The destination dimension size - /// The radius, and scaling factor - protected (float radius, float scale, float ratio) GetSamplingRadius(int sourceSize, int destinationSize) - { - float ratio = (float)sourceSize / destinationSize; - float scale = ratio; - - if (scale < 1F) - { - scale = 1F; - } - - return (MathF.Ceiling(scale * this.Sampler.Radius), scale, ratio); - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index 50af26aebf..bfde1769c1 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -5,13 +5,9 @@ using System; using System.Collections.Generic; using System.Linq; using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; 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.Transforms @@ -20,22 +16,28 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// Provides the base methods to perform non-affine transforms on an image. /// /// The pixel format. - internal class ProjectiveTransformProcessor : InterpolatedTransformProcessorBase + internal class ProjectiveTransformProcessor : TransformProcessorBase where TPixel : struct, IPixel { /// /// Initializes a new instance of the class. /// - /// The transform matrix + /// The transform matrix. /// The sampler to perform the transform operation. - /// The target dimensions to constrain the transformed image to. - public ProjectiveTransformProcessor(Matrix4x4 matrix, IResampler sampler, Size targetDimensions) - : base(sampler) + /// The source image size. + public ProjectiveTransformProcessor(Matrix4x4 matrix, IResampler sampler, Size sourceSize) { + Guard.NotNull(sampler, nameof(sampler)); + this.Sampler = sampler; this.TransformMatrix = matrix; - this.TargetDimensions = targetDimensions; + this.TargetDimensions = TransformUtils.GetTransformedSize(sourceSize, matrix); } + /// + /// Gets the sampler to perform interpolation of the transform operation. + /// + public IResampler Sampler { get; } + /// /// Gets the matrix used to supply the projective transform /// @@ -60,17 +62,21 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// protected override void OnFrameApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle, Configuration configuration) { + // Handle tranforms that result in output identical to the original. + if (this.TransformMatrix.Equals(default) || this.TransformMatrix.Equals(Matrix4x4.Identity)) + { + // The cloned will be blank here copy all the pixel data over + source.GetPixelSpan().CopyTo(destination.GetPixelSpan()); + return; + } + int height = this.TargetDimensions.Height; int width = this.TargetDimensions.Width; - Rectangle sourceBounds = source.Bounds(); - var targetBounds = new Rectangle(0, 0, width, height); - - // Since could potentially be resizing the canvas we might need to re-calculate the matrix - Matrix4x4 matrix = this.GetProcessingMatrix(sourceBounds, targetBounds); + var targetBounds = new Rectangle(Point.Empty, this.TargetDimensions); // Convert from screen to world space. - Matrix4x4.Invert(matrix, out matrix); + Matrix4x4.Invert(this.TransformMatrix, out Matrix4x4 matrix); const float Epsilon = 0.0000001F; if (this.Sampler is NearestNeighborResampler) @@ -92,7 +98,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int px = (int)MathF.Round(v3.X / z); int py = (int)MathF.Round(v3.Y / z); - if (sourceBounds.Contains(px, py)) + if (sourceRectangle.Contains(px, py)) { destRow[x] = source[px, py]; } @@ -103,145 +109,40 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return; } - int maxSourceX = source.Width - 1; - int maxSourceY = source.Height - 1; - (float radius, float scale, float ratio) xRadiusScale = this.GetSamplingRadius(source.Width, destination.Width); - (float radius, float scale, float ratio) yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height); - float xScale = xRadiusScale.scale; - float yScale = yRadiusScale.scale; - - // Using Vector4 with dummy 0-s, because Vector2 SIMD implementation is not reliable: - var radius = new Vector4(xRadiusScale.radius, yRadiusScale.radius, 0, 0); - - IResampler sampler = this.Sampler; - var maxSource = new Vector4(maxSourceX, maxSourceY, maxSourceX, maxSourceY); - int xLength = (int)MathF.Ceiling((radius.X * 2) + 2); - int yLength = (int)MathF.Ceiling((radius.Y * 2) + 2); - - MemoryAllocator memoryAllocator = configuration.MemoryAllocator; - - using (Buffer2D yBuffer = memoryAllocator.Allocate2D(yLength, height)) - using (Buffer2D xBuffer = memoryAllocator.Allocate2D(xLength, height)) + var kernel = new TransformKernelMap(configuration, source.Size(), destination.Size(), this.Sampler); + try { - ParallelHelper.IterateRows( + ParallelHelper.IterateRowsWithTempBuffer( targetBounds, configuration, - rows => + (rows, vectorBuffer) => + { + Span vectorSpan = vectorBuffer.Span; + for (int y = rows.Min; y < rows.Max; y++) { - for (int y = rows.Min; y < rows.Max; 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++) - { - // 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; + Span targetRowSpan = destination.GetPixelRowSpan(y); + PixelOperations.Instance.ToVector4(configuration, targetRowSpan, vectorSpan); + ref float ySpanRef = ref kernel.GetYStartReference(y); + ref float xSpanRef = ref kernel.GetXStartReference(y); - 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); - - // Values are first premultiplied to prevent darkening of edge pixels - var current = source[i, j].ToVector4(); - Vector4Utils.Premultiply(ref current); - sum += current * xWeight * yWeight; - } - } - - ref TPixel dest = ref Unsafe.Add(ref destRowRef, x); + for (int x = 0; x < width; x++) + { + // 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); + Vector2 point = new Vector2(v3.X, v3.Y) / MathF.Max(v3.Z, Epsilon); - // Reverse the premultiplication - Vector4Utils.UnPremultiply(ref sum); - dest.FromVector4(sum); - } + kernel.Convolve(point, x, ref ySpanRef, ref xSpanRef, source.PixelBuffer, vectorSpan); } - }); + + PixelOperations.Instance.FromVector4(configuration, vectorSpan, targetRowSpan); + } + }); + } + finally + { + kernel.Dispose(); } } - - /// - /// Gets a transform matrix adjusted for final processing based upon the target image bounds. - /// - /// The source image bounds. - /// The destination image bounds. - /// - /// The . - /// - protected virtual Matrix4x4 GetProcessingMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle) => this.TransformMatrix; } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformHelpers.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformHelpers.cs deleted file mode 100644 index 2e85f6c2cc..0000000000 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformHelpers.cs +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using SixLabors.ImageSharp.MetaData.Profiles.Exif; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Processing.Processors.Transforms -{ - /// - /// Contains helper methods for working with affine and non-affine transforms - /// - internal static class TransformHelpers - { - /// - /// Updates the dimensional metadata of a transformed image - /// - /// The pixel format. - /// The image to update - public static void UpdateDimensionalMetData(Image image) - where TPixel : struct, IPixel - { - ExifProfile profile = image.MetaData.ExifProfile; - if (profile is null) - { - return; - } - - // Removing the previously stored value allows us to set a value with our own data tag if required. - if (profile.GetValue(ExifTag.PixelXDimension) != null) - { - profile.RemoveValue(ExifTag.PixelXDimension); - - if (image.Width <= ushort.MaxValue) - { - profile.SetValue(ExifTag.PixelXDimension, (ushort)image.Width); - } - else - { - profile.SetValue(ExifTag.PixelXDimension, (uint)image.Width); - } - } - - if (profile.GetValue(ExifTag.PixelYDimension) != null) - { - profile.RemoveValue(ExifTag.PixelYDimension); - - if (image.Height <= ushort.MaxValue) - { - profile.SetValue(ExifTag.PixelYDimension, (ushort)image.Height); - } - else - { - profile.SetValue(ExifTag.PixelYDimension, (uint)image.Height); - } - } - } - - /// - /// Gets the centered transform matrix based upon the source and destination rectangles - /// - /// The source image bounds. - /// The destination image bounds. - /// The transformation matrix. - /// The - public static Matrix3x2 GetCenteredTransformMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle, Matrix3x2 matrix) - { - // We invert the matrix to handle the transformation from screen to world space. - // This ensures scaling matrices are correct. - Matrix3x2.Invert(matrix, out Matrix3x2 inverted); - - var translationToTargetCenter = Matrix3x2.CreateTranslation(-destinationRectangle.Width * .5F, -destinationRectangle.Height * .5F); - var translateToSourceCenter = Matrix3x2.CreateTranslation(sourceRectangle.Width * .5F, sourceRectangle.Height * .5F); - - Matrix3x2.Invert(translationToTargetCenter * inverted * translateToSourceCenter, out Matrix3x2 centered); - - // Translate back to world to pass to the Transform method. - return centered; - } - - /// - /// Gets the centered transform matrix based upon the source and destination rectangles - /// - /// The source image bounds. - /// The destination image bounds. - /// The transformation matrix. - /// The - public static Matrix4x4 GetCenteredTransformMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle, Matrix4x4 matrix) - { - // We invert the matrix to handle the transformation from screen to world space. - // This ensures scaling matrices are correct. - Matrix4x4.Invert(matrix, out Matrix4x4 inverted); - - var translationToTargetCenter = Matrix4x4.CreateTranslation(-destinationRectangle.Width * .5F, -destinationRectangle.Height * .5F, 0); - var translateToSourceCenter = Matrix4x4.CreateTranslation(sourceRectangle.Width * .5F, sourceRectangle.Height * .5F, 0); - - Matrix4x4.Invert(translationToTargetCenter * inverted * translateToSourceCenter, out Matrix4x4 centered); - - // Translate back to world to pass to the Transform method. - return centered; - } - - /// - /// Returns the bounding rectangle relative to the source for the given transformation matrix. - /// - /// The source rectangle. - /// The transformation matrix. - /// - /// The . - /// - public static Rectangle GetTransformedBoundingRectangle(Rectangle rectangle, Matrix4x4 matrix) - { - // Calculate the position of the four corners in world space by applying - // The world matrix to the four corners in object space (0, 0, width, height) - var tl = Vector2.Transform(Vector2.Zero, matrix); - var tr = Vector2.Transform(new Vector2(rectangle.Width, 0), matrix); - var bl = Vector2.Transform(new Vector2(0, rectangle.Height), matrix); - var br = Vector2.Transform(new Vector2(rectangle.Width, rectangle.Height), matrix); - - return GetBoundingRectangle(tl, tr, bl, br); - } - - private static Rectangle GetBoundingRectangle(Vector2 tl, Vector2 tr, Vector2 bl, Vector2 br) - { - // Find the minimum and maximum "corners" based on the given vectors - float minX = MathF.Min(tl.X, MathF.Min(tr.X, MathF.Min(bl.X, br.X))); - float maxX = MathF.Max(tl.X, MathF.Max(tr.X, MathF.Max(bl.X, br.X))); - float minY = MathF.Min(tl.Y, MathF.Min(tr.Y, MathF.Min(bl.Y, br.Y))); - float maxY = MathF.Max(tl.Y, MathF.Max(tr.Y, MathF.Max(bl.Y, br.Y))); - float sizeX = maxX - minX + .5F; - float sizeY = maxY - minY + .5F; - - return new Rectangle((int)(MathF.Ceiling(minX) - .5F), (int)(MathF.Ceiling(minY) - .5F), (int)MathF.Floor(sizeX), (int)MathF.Floor(sizeY)); - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorBase.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorBase.cs index 13ee90a062..4973b90f46 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorBase.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorBase.cs @@ -16,6 +16,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { /// protected override void AfterImageApply(Image source, Image destination, Rectangle sourceRectangle) - => TransformHelpers.UpdateDimensionalMetData(destination); + => TransformProcessorHelpers.UpdateDimensionalMetData(destination); } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs new file mode 100644 index 0000000000..f5536d0467 --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs @@ -0,0 +1,58 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.MetaData.Profiles.Exif; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Processing.Processors.Transforms +{ + /// + /// Contains helper methods for working with transforms. + /// + internal static class TransformProcessorHelpers + { + /// + /// Updates the dimensional metadata of a transformed image + /// + /// The pixel format. + /// The image to update + public static void UpdateDimensionalMetData(Image image) + where TPixel : struct, IPixel + { + ExifProfile profile = image.MetaData.ExifProfile; + if (profile is null) + { + return; + } + + // Removing the previously stored value allows us to set a value with our own data tag if required. + if (profile.GetValue(ExifTag.PixelXDimension) != null) + { + profile.RemoveValue(ExifTag.PixelXDimension); + + if (image.Width <= ushort.MaxValue) + { + profile.SetValue(ExifTag.PixelXDimension, (ushort)image.Width); + } + else + { + profile.SetValue(ExifTag.PixelXDimension, (uint)image.Width); + } + } + + if (profile.GetValue(ExifTag.PixelYDimension) != null) + { + profile.RemoveValue(ExifTag.PixelYDimension); + + if (image.Height <= ushort.MaxValue) + { + profile.SetValue(ExifTag.PixelYDimension, (ushort)image.Height); + } + else + { + profile.SetValue(ExifTag.PixelYDimension, (uint)image.Height); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs index 10cf49c34b..f561d3513f 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs @@ -58,6 +58,111 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return centered; } + /// + /// Creates a matrix that performs a tapering projective transform. + /// + /// + /// The rectangular size of the image being transformed. + /// An enumeration that indicates the side of the rectangle that tapers. + /// An enumeration that indicates on which corners to taper the rectangle. + /// The amount to taper. + /// The + public static Matrix4x4 CreateTaperMatrix(Size size, TaperSide side, TaperCorner corner, float fraction) + { + Matrix4x4 matrix = Matrix4x4.Identity; + + switch (side) + { + case TaperSide.Left: + matrix.M11 = fraction; + matrix.M22 = fraction; + matrix.M13 = (fraction - 1) / size.Width; + + switch (corner) + { + case TaperCorner.RightOrBottom: + break; + + case TaperCorner.LeftOrTop: + matrix.M12 = size.Height * matrix.M13; + matrix.M32 = size.Height * (1 - fraction); + break; + + case TaperCorner.Both: + matrix.M12 = size.Height * .5F * matrix.M13; + matrix.M32 = size.Height * (1 - fraction) / 2; + break; + } + + break; + + case TaperSide.Top: + matrix.M11 = fraction; + matrix.M22 = fraction; + matrix.M23 = (fraction - 1) / size.Height; + + switch (corner) + { + case TaperCorner.RightOrBottom: + break; + + case TaperCorner.LeftOrTop: + matrix.M21 = size.Width * matrix.M23; + matrix.M31 = size.Width * (1 - fraction); + break; + + case TaperCorner.Both: + matrix.M21 = size.Width * .5F * matrix.M23; + matrix.M31 = size.Width * (1 - fraction) / 2; + break; + } + + break; + + case TaperSide.Right: + matrix.M11 = 1 / fraction; + matrix.M13 = (1 - fraction) / (size.Width * fraction); + + switch (corner) + { + case TaperCorner.RightOrBottom: + break; + + case TaperCorner.LeftOrTop: + matrix.M12 = size.Height * matrix.M13; + break; + + case TaperCorner.Both: + matrix.M12 = size.Height * .5F * matrix.M13; + break; + } + + break; + + case TaperSide.Bottom: + matrix.M22 = 1 / fraction; + matrix.M23 = (1 - fraction) / (size.Height * fraction); + + switch (corner) + { + case TaperCorner.RightOrBottom: + break; + + case TaperCorner.LeftOrTop: + matrix.M21 = size.Width * matrix.M23; + break; + + case TaperCorner.Both: + matrix.M21 = size.Width * .5F * matrix.M23; + break; + } + + break; + } + + return matrix; + } + /// /// Returns the rectangle bounds relative to the source for the given transformation matrix. /// @@ -114,6 +219,63 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Rectangle rectangle = GetTransformedRectangle(new Rectangle(Point.Empty, size), matrix); + return ConstrainSize(rectangle); + } + + /// + /// Returns the rectangle relative to the source for the given transformation matrix. + /// + /// The source rectangle. + /// The transformation matrix. + /// + /// The . + /// + public static Rectangle GetTransformedRectangle(Rectangle rectangle, Matrix4x4 matrix) + { + if (rectangle.Equals(default) || Matrix4x4.Identity.Equals(matrix)) + { + return rectangle; + } + + Vector2 GetVector(float x, float y) + { + const float Epsilon = 0.0000001F; + var v3 = Vector3.Transform(new Vector3(x, y, 1F), matrix); + return new Vector2(v3.X, v3.Y) / MathF.Max(v3.Z, Epsilon); + } + + Vector2 tl = GetVector(rectangle.Left, rectangle.Top); + Vector2 tr = GetVector(rectangle.Right, rectangle.Top); + Vector2 bl = GetVector(rectangle.Left, rectangle.Bottom); + Vector2 br = GetVector(rectangle.Right, rectangle.Bottom); + + return GetBoundingRectangle(tl, tr, bl, br); + } + + /// + /// Returns the size relative to the source for the given transformation matrix. + /// + /// The source size. + /// The transformation matrix. + /// + /// The . + /// + public static Size GetTransformedSize(Size size, Matrix4x4 matrix) + { + Guard.IsTrue(size.Width > 0 && size.Height > 0, nameof(size), "Source size dimensions cannot be 0!"); + + if (matrix.Equals(default) || matrix.Equals(Matrix4x4.Identity)) + { + return size; + } + + Rectangle rectangle = GetTransformedRectangle(new Rectangle(Point.Empty, size), matrix); + + return ConstrainSize(rectangle); + } + + private static Size ConstrainSize(Rectangle rectangle) + { // We want to resize the canvas here taking into account any translations. int height = rectangle.Top < 0 ? rectangle.Bottom : Math.Max(rectangle.Height, rectangle.Bottom); int width = rectangle.Left < 0 ? rectangle.Right : Math.Max(rectangle.Width, rectangle.Right); diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs new file mode 100644 index 0000000000..3edc993c47 --- /dev/null +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -0,0 +1,113 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Collections.Generic; +using System.Numerics; +using SixLabors.ImageSharp.Processing.Processors.Transforms; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing +{ + /// + /// A helper class for constructing instances for use in projective transforms. + /// + public class ProjectiveTransformBuilder + { + private readonly List matrices = new List(); + private Rectangle rectangle; + + /// + /// Initializes a new instance of the class. + /// + /// The source image size. + public ProjectiveTransformBuilder(Size sourceSize) => this.Size = sourceSize; + + /// + /// Initializes a new instance of the class. + /// + /// The source rectangle. + public ProjectiveTransformBuilder(Rectangle sourceRectangle) + : this(sourceRectangle.Size) + => this.rectangle = sourceRectangle; + + /// + /// Gets the source image size. + /// + internal Size Size { get; } + + /// + /// Prepends a matrix that performs a tapering projective transform. + /// + /// An enumeration that indicates the side of the rectangle that tapers. + /// An enumeration that indicates on which corners to taper the rectangle. + /// The amount to taper. + /// The . + public ProjectiveTransformBuilder PrependTaperMatrix(TaperSide side, TaperCorner corner, float fraction) + { + this.matrices.Insert(0, TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); + return this; + } + + /// + /// Appends a matrix that performs a tapering projective transform. + /// + /// An enumeration that indicates the side of the rectangle that tapers. + /// An enumeration that indicates on which corners to taper the rectangle. + /// The amount to taper. + /// The . + public ProjectiveTransformBuilder AppendTaperMatrix(TaperSide side, TaperCorner corner, float fraction) + { + this.matrices.Add(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); + return this; + } + + /// + /// Prepends a raw matrix. + /// + /// The matrix to prepend. + /// The . + public ProjectiveTransformBuilder PrependMatrix(Matrix4x4 matrix) + { + this.matrices.Insert(0, matrix); + return this; + } + + /// + /// Appends a raw matrix. + /// + /// The matrix to append. + /// The . + public ProjectiveTransformBuilder AppendMatrix(Matrix4x4 matrix) + { + this.matrices.Add(matrix); + return this; + } + + /// + /// Returns the combined matrix. + /// + /// The . + public Matrix4x4 BuildMatrix() + { + Matrix4x4 matrix = Matrix4x4.Identity; + + // Translate the origin matrix to cater for source rectangle offsets. + if (!this.rectangle.Equals(default)) + { + matrix *= Matrix4x4.CreateTranslation(new Vector3(-this.rectangle.Location, 0)); + } + + foreach (Matrix4x4 m in this.matrices) + { + matrix *= m; + } + + return matrix; + } + + /// + /// Removes all matrices from the builder. + /// + public void Clear() => this.matrices.Clear(); + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/ProjectiveTransformHelper.cs b/src/ImageSharp/Processing/ProjectiveTransformHelper.cs deleted file mode 100644 index 4057ec586c..0000000000 --- a/src/ImageSharp/Processing/ProjectiveTransformHelper.cs +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Numerics; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Processing -{ - /// - /// Enumerates the various options which determine which side to taper - /// - public enum TaperSide - { - /// - /// Taper the left side - /// - Left, - - /// - /// Taper the top side - /// - Top, - - /// - /// Taper the right side - /// - Right, - - /// - /// Taper the bottom side - /// - Bottom - } - - /// - /// Enumerates the various options which determine how to taper corners - /// - public enum TaperCorner - { - /// - /// Taper the left or top corner - /// - LeftOrTop, - - /// - /// Taper the right or bottom corner - /// - RightOrBottom, - - /// - /// Taper the both sets of corners - /// - Both - } - - /// - /// Provides helper methods for working with generalized projective transforms. - /// - public static class ProjectiveTransformHelper - { - /// - /// Creates a matrix that performs a tapering projective transform. - /// - /// - /// The rectangular size of the image being transformed. - /// An enumeration that indicates the side of the rectangle that tapers. - /// An enumeration that indicates on which corners to taper the rectangle. - /// The amount to taper. - /// The - public static Matrix4x4 CreateTaperMatrix(Size size, TaperSide taperSide, TaperCorner taperCorner, float taperFraction) - { - Matrix4x4 matrix = Matrix4x4.Identity; - - switch (taperSide) - { - case TaperSide.Left: - matrix.M11 = taperFraction; - matrix.M22 = taperFraction; - matrix.M13 = (taperFraction - 1) / size.Width; - - switch (taperCorner) - { - case TaperCorner.RightOrBottom: - break; - - case TaperCorner.LeftOrTop: - matrix.M12 = size.Height * matrix.M13; - matrix.M32 = size.Height * (1 - taperFraction); - break; - - case TaperCorner.Both: - matrix.M12 = (size.Height * 0.5f) * matrix.M13; - matrix.M32 = size.Height * (1 - taperFraction) / 2; - break; - } - - break; - - case TaperSide.Top: - matrix.M11 = taperFraction; - matrix.M22 = taperFraction; - matrix.M23 = (taperFraction - 1) / size.Height; - - switch (taperCorner) - { - case TaperCorner.RightOrBottom: - break; - - case TaperCorner.LeftOrTop: - matrix.M21 = size.Width * matrix.M23; - matrix.M31 = size.Width * (1 - taperFraction); - break; - - case TaperCorner.Both: - matrix.M21 = (size.Width * 0.5f) * matrix.M23; - matrix.M31 = size.Width * (1 - taperFraction) / 2; - break; - } - - break; - - case TaperSide.Right: - matrix.M11 = 1 / taperFraction; - matrix.M13 = (1 - taperFraction) / (size.Width * taperFraction); - - switch (taperCorner) - { - case TaperCorner.RightOrBottom: - break; - - case TaperCorner.LeftOrTop: - matrix.M12 = size.Height * matrix.M13; - break; - - case TaperCorner.Both: - matrix.M12 = (size.Height * 0.5f) * matrix.M13; - break; - } - - break; - - case TaperSide.Bottom: - matrix.M22 = 1 / taperFraction; - matrix.M23 = (1 - taperFraction) / (size.Height * taperFraction); - - switch (taperCorner) - { - case TaperCorner.RightOrBottom: - break; - - case TaperCorner.LeftOrTop: - matrix.M21 = size.Width * matrix.M23; - break; - - case TaperCorner.Both: - matrix.M21 = (size.Width * 0.5f) * matrix.M23; - break; - } - - break; - } - - return matrix; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Processing/TaperCorner.cs b/src/ImageSharp/Processing/TaperCorner.cs new file mode 100644 index 0000000000..395b171424 --- /dev/null +++ b/src/ImageSharp/Processing/TaperCorner.cs @@ -0,0 +1,26 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Processing +{ + /// + /// Enumerates the various options which determine how to taper corners + /// + public enum TaperCorner + { + /// + /// Taper the left or top corner + /// + LeftOrTop, + + /// + /// Taper the right or bottom corner + /// + RightOrBottom, + + /// + /// Taper the both sets of corners + /// + Both + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/TaperSide.cs b/src/ImageSharp/Processing/TaperSide.cs new file mode 100644 index 0000000000..226d11aed2 --- /dev/null +++ b/src/ImageSharp/Processing/TaperSide.cs @@ -0,0 +1,31 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Processing +{ + /// + /// Enumerates the various options which determine which side to taper + /// + public enum TaperSide + { + /// + /// Taper the left side + /// + Left, + + /// + /// Taper the top side + /// + Top, + + /// + /// Taper the right side + /// + Right, + + /// + /// Taper the bottom side + /// + Bottom + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/TransformExtensions.cs b/src/ImageSharp/Processing/TransformExtensions.cs index 4cbd1b041f..ea789eb3d7 100644 --- a/src/ImageSharp/Processing/TransformExtensions.cs +++ b/src/ImageSharp/Processing/TransformExtensions.cs @@ -1,10 +1,8 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System.Numerics; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Transforms; -using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing { @@ -14,7 +12,7 @@ namespace SixLabors.ImageSharp.Processing public static class TransformExtensions { /// - /// Transforms an image by the given matrix. + /// Performs an affine transform of an image. /// /// The pixel format. /// The image to transform. @@ -25,7 +23,7 @@ namespace SixLabors.ImageSharp.Processing => Transform(source, builder, KnownResamplers.Bicubic); /// - /// Transforms an image by the given matrix using the specified sampling algorithm. + /// Performs an affine transform of an image using the specified sampling algorithm. /// /// The pixel format. /// The image to transform. @@ -37,44 +35,26 @@ namespace SixLabors.ImageSharp.Processing => source.ApplyProcessor(new AffineTransformProcessor(builder.BuildMatrix(), sampler, builder.Size)); /// - /// Transforms an image by the given matrix. + /// Performs a projective transform of an image. /// /// The pixel format. /// The image to transform. - /// The transformation matrix. - /// The - public static IImageProcessingContext Transform(this IImageProcessingContext source, Matrix4x4 matrix) - where TPixel : struct, IPixel - => Transform(source, matrix, KnownResamplers.Bicubic); - - /// - /// Applies a projective transform to the image by the given matrix using the specified sampling algorithm. - /// - /// The pixel format. - /// The image to transform. - /// The transformation matrix. - /// The to perform the resampling. + /// The affine transform builder. /// The - public static IImageProcessingContext Transform(this IImageProcessingContext source, Matrix4x4 matrix, IResampler sampler) + public static IImageProcessingContext Transform(this IImageProcessingContext source, ProjectiveTransformBuilder builder) where TPixel : struct, IPixel - => source.ApplyProcessor(new ProjectiveTransformProcessor(matrix, sampler, source.GetCurrentSize())); + => Transform(source, builder, KnownResamplers.Bicubic); /// - /// Applies a projective transform to the image by the given matrix using the specified sampling algorithm. - /// TODO: Should we be offsetting the matrix here? + /// Performs a projective transform of an image using the specified sampling algorithm. /// /// The pixel format. /// The image to transform. - /// The transformation matrix. + /// The projective transform builder. /// The to perform the resampling. - /// The rectangle to constrain the transformed image to. /// The - internal static IImageProcessingContext Transform(this IImageProcessingContext source, Matrix4x4 matrix, IResampler sampler, Rectangle rectangle) + public static IImageProcessingContext Transform(this IImageProcessingContext source, ProjectiveTransformBuilder builder, IResampler sampler) where TPixel : struct, IPixel - { - var t = Matrix4x4.CreateTranslation(new Vector3(-rectangle.Location, 0)); - Matrix4x4 combinedMatrix = t * matrix; - return source.ApplyProcessor(new ProjectiveTransformProcessor(combinedMatrix, sampler, rectangle.Size)); - } + => source.ApplyProcessor(new ProjectiveTransformProcessor(builder.BuildMatrix(), sampler, builder.Size)); } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index 32280d48cd..e05a8e381b 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) - .AppendRotateMatrixDegrees((float)Math.PI / 4F); + .AppendRotateMatrixDegrees(30); image.Mutate(c => c.Transform(builder, resampler)); image.DebugSave(provider, resamplerName); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs index 5190a71e71..0362d75a0b 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), @@ -60,10 +60,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms }; - public ProjectiveTransformTests(ITestOutputHelper output) - { - this.Output = output; - } + public ProjectiveTransformTests(ITestOutputHelper output) => this.Output = output; [Theory] [WithTestPatternImages(nameof(ResamplerNames), 150, 150, PixelTypes.Rgba32)] @@ -73,9 +70,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms IResampler sampler = GetResampler(resamplerName); using (Image image = provider.GetImage()) { - Matrix4x4 m = ProjectiveTransformHelper.CreateTaperMatrix(image.Size(), TaperSide.Right, TaperCorner.Both, .5F); + ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder(image.Size()) + .AppendTaperMatrix(TaperSide.Right, TaperCorner.Both, .5F); - image.Mutate(i => { i.Transform(m, sampler); }); + image.Mutate(i => i.Transform(builder, sampler)); image.DebugSave(provider, resamplerName); image.CompareToReferenceOutput(ValidatorComparer, provider, resamplerName); @@ -89,8 +87,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { using (Image image = provider.GetImage()) { - Matrix4x4 m = ProjectiveTransformHelper.CreateTaperMatrix(image.Size(), taperSide, taperCorner, .5F); - image.Mutate(i => { i.Transform(m); }); + ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder(image.Size()) + .AppendTaperMatrix(taperSide, taperCorner, .5F); + + image.Mutate(i => i.Transform(builder)); FormattableString testOutputDetails = $"{taperSide}-{taperCorner}"; image.DebugSave(provider, testOutputDetails); @@ -110,10 +110,13 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms // https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/transforms/non-affine using (Image image = provider.GetImage()) { - Matrix4x4 m = Matrix4x4.Identity; - m.M13 = 0.01F; + Matrix4x4 matrix = Matrix4x4.Identity; + matrix.M13 = 0.01F; + + ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder(image.Size()) + .AppendMatrix(matrix); - image.Mutate(i => { i.Transform(m); }); + image.Mutate(i => i.Transform(builder)); image.DebugSave(provider); image.CompareToReferenceOutput(TolerantComparer, provider); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs index 146ed62304..909e505357 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms Assert.Equal(ExifDataType.Long, profile.GetValue(ExifTag.PixelXDimension).DataType); Assert.Equal(ExifDataType.Long, profile.GetValue(ExifTag.PixelYDimension).DataType); - TransformHelpers.UpdateDimensionalMetData(img); + TransformProcessorHelpers.UpdateDimensionalMetData(img); Assert.Equal(ExifDataType.Short, profile.GetValue(ExifTag.PixelXDimension).DataType); Assert.Equal(ExifDataType.Short, profile.GetValue(ExifTag.PixelYDimension).DataType); From 8b0e276de532d4900b722c75099bb3f9d20235ff Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 10 Nov 2018 21:45:02 +0000 Subject: [PATCH 329/381] 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 ed8a7b0b6f..e7e0f1311d 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit ed8a7b0b6fe1b2e2a7c822aa617103ae31192655 +Subproject commit e7e0f1311d1d585ea8e38efb5a69fca98c44e8a4 From 657f551642a3e2773cf72534a886ffc63241e9dc Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Sat, 10 Nov 2018 17:25:39 -0600 Subject: [PATCH 330/381] ImageSharp-762_Aot-compiling: added simple unit test to check no exceptions are thrown by AotCompiler --- .../Advanced/AotCompilerTests.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs diff --git a/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs b/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs new file mode 100644 index 0000000000..3d6faa27ec --- /dev/null +++ b/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs @@ -0,0 +1,18 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Advanced +{ + public class AotCompilerTests + { + [Fact] + public void AotCompiler_NoExceptions() + { + AotCompiler.Seed(); + } + } +} From 15093ba8bff157d0daac92e61e87333779eaa91e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 11 Nov 2018 10:24:32 +0000 Subject: [PATCH 331/381] Change tolerance for 32bit framework builds. --- .../Processing/Transforms/AffineTransformTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index e05a8e381b..15b4500bb2 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -17,7 +17,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { private readonly ITestOutputHelper Output; - private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.0085f, 3); + // 1 byte difference on one color component. + private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.0134F, 3); /// /// angleDeg, sx, sy, tx, ty From 88da4bcba303c335d457edce326e1640c972e167 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 11 Nov 2018 21:28:53 +0100 Subject: [PATCH 332/381] make code more clear by extracting the ratio to a variable again while keeping it inlined to avoid it in the third case, and while still replacing the division by a multiplication in the second case. --- src/ImageSharp/Processing/ResizeHelper.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Processing/ResizeHelper.cs b/src/ImageSharp/Processing/ResizeHelper.cs index 92af89d9e8..aaac7346d7 100644 --- a/src/ImageSharp/Processing/ResizeHelper.cs +++ b/src/ImageSharp/Processing/ResizeHelper.cs @@ -343,13 +343,15 @@ namespace SixLabors.ImageSharp.Processing if (widthDiff < heightDiff) { - destinationHeight = (int)MathF.Round(width * ((float)sourceHeight / sourceWidth)); + float sourceRatio = (float)sourceHeight / sourceWidth; + destinationHeight = (int)MathF.Round(width * sourceRatio); height = destinationHeight; destinationWidth = width; } else if (widthDiff > heightDiff) { - destinationWidth = (int)MathF.Round(height * ((float)sourceWidth / sourceHeight)); + float sourceRatioInverse = (float)sourceWidth / sourceHeight; + destinationWidth = (int)MathF.Round(height * sourceRatioInverse); destinationHeight = height; width = destinationWidth; } From f6618a6f3aeafe0dc14f82993e197d3c99958975 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 11 Nov 2018 21:30:19 +0100 Subject: [PATCH 333/381] inline percentHeiught and percentWidth as they are used only in one case each --- src/ImageSharp/Processing/ResizeHelper.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Processing/ResizeHelper.cs b/src/ImageSharp/Processing/ResizeHelper.cs index aaac7346d7..3ae632162f 100644 --- a/src/ImageSharp/Processing/ResizeHelper.cs +++ b/src/ImageSharp/Processing/ResizeHelper.cs @@ -333,10 +333,6 @@ namespace SixLabors.ImageSharp.Processing return (new Size(sourceWidth, sourceWidth), new Rectangle(0, 0, sourceWidth, sourceHeight)); } - // Fractional variants for preserving aspect ratio. - float percentHeight = MathF.Abs(height / (float)sourceHeight); - float percentWidth = MathF.Abs(width / (float)sourceWidth); - // Find the shortest distance to go. int widthDiff = sourceWidth - width; int heightDiff = sourceHeight - height; @@ -360,12 +356,14 @@ namespace SixLabors.ImageSharp.Processing if (height > width) { destinationWidth = width; + float percentWidth = MathF.Abs(width / (float)sourceWidth); destinationHeight = (int)MathF.Round(sourceHeight * percentWidth); height = destinationHeight; } else { destinationHeight = height; + float percentHeight = MathF.Abs(height / (float)sourceHeight); destinationWidth = (int)MathF.Round(sourceWidth * percentHeight); width = destinationWidth; } From 13b9e9c596dc6ca02e1f4c52b6bb6607791ab133 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 11 Nov 2018 21:33:39 +0000 Subject: [PATCH 334/381] Improve transform builder coverage --- .../Processing/AffineTransformBuilder.cs | 16 ++++++++-------- .../Processing/ProjectiveTransformBuilder.cs | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index ff44915b14..b2b011264a 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Processing /// The . public AffineTransformBuilder PrependRotateMatrixDegrees(float degrees) { - this.matrices.Insert(0, TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); + this.PrependMatrix(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); return this; } @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Processing /// The . public AffineTransformBuilder AppendRotateMatrixDegrees(float degrees) { - this.matrices.Add(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); + this.AppendMatrix(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); return this; } @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Processing /// The . public AffineTransformBuilder PrependScaleMatrix(SizeF scales) { - this.matrices.Insert(0, Matrix3x2Extensions.CreateScale(scales)); + this.PrependMatrix(Matrix3x2Extensions.CreateScale(scales)); return this; } @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Processing /// The . public AffineTransformBuilder AppendScaleMatrix(SizeF scales) { - this.matrices.Add(Matrix3x2Extensions.CreateScale(scales)); + this.AppendMatrix(Matrix3x2Extensions.CreateScale(scales)); return this; } @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.Processing /// The . public AffineTransformBuilder PrependSkewMatrixDegrees(float degreesX, float degreesY) { - this.matrices.Insert(0, TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); + this.PrependMatrix(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); return this; } @@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.Processing /// The . public AffineTransformBuilder AppendSkewMatrixDegrees(float degreesX, float degreesY) { - this.matrices.Add(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); + this.AppendMatrix(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); return this; } @@ -110,7 +110,7 @@ namespace SixLabors.ImageSharp.Processing /// The . public AffineTransformBuilder PrependTranslationMatrix(PointF position) { - this.matrices.Insert(0, Matrix3x2Extensions.CreateTranslation(position)); + this.PrependMatrix(Matrix3x2Extensions.CreateTranslation(position)); return this; } @@ -121,7 +121,7 @@ namespace SixLabors.ImageSharp.Processing /// The . public AffineTransformBuilder AppendTranslationMatrix(PointF position) { - this.matrices.Add(Matrix3x2Extensions.CreateTranslation(position)); + this.AppendMatrix(Matrix3x2Extensions.CreateTranslation(position)); return this; } diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index 3edc993c47..529dd56b19 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Processing /// The . public ProjectiveTransformBuilder PrependTaperMatrix(TaperSide side, TaperCorner corner, float fraction) { - this.matrices.Insert(0, TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); + this.PrependMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); return this; } @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing /// The . public ProjectiveTransformBuilder AppendTaperMatrix(TaperSide side, TaperCorner corner, float fraction) { - this.matrices.Add(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); + this.AppendMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); return this; } From 8a47a1894b5d312fb697b1d49d52556fcd63c526 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 11 Nov 2018 22:42:05 +0000 Subject: [PATCH 335/381] Cleanup and add dedicated transform builder tests --- .../Processing/AffineTransformBuilder.cs | 48 ++++------- .../Processing/ProjectiveTransformBuilder.cs | 18 ++--- .../Transforms/AffineTransformBuilderTests.cs | 79 +++++++++++++++++++ .../ProjectiveTransformBuilderTests.cs | 78 ++++++++++++++++++ 4 files changed, 181 insertions(+), 42 deletions(-) create mode 100644 tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs create mode 100644 tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index b2b011264a..003249d6ed 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -20,7 +20,13 @@ namespace SixLabors.ImageSharp.Processing /// Initializes a new instance of the class. /// /// The source image size. - public AffineTransformBuilder(Size sourceSize) => this.Size = sourceSize; + public AffineTransformBuilder(Size sourceSize) + { + Guard.MustBeGreaterThan(sourceSize.Width, 0, nameof(sourceSize)); + Guard.MustBeGreaterThan(sourceSize.Height, 0, nameof(sourceSize)); + + this.Size = sourceSize; + } /// /// Initializes a new instance of the class. @@ -41,10 +47,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in degrees. /// The . public AffineTransformBuilder PrependRotateMatrixDegrees(float degrees) - { - this.PrependMatrix(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); - return this; - } + => this.PrependMatrix(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); /// /// Appends a centered rotation matrix using the given rotation in degrees. @@ -52,10 +55,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in degrees. /// The . public AffineTransformBuilder AppendRotateMatrixDegrees(float degrees) - { - this.AppendMatrix(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); - return this; - } + => this.AppendMatrix(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); /// /// Prepends a scale matrix from the given vector scale. @@ -63,10 +63,7 @@ namespace SixLabors.ImageSharp.Processing /// The horizontal and vertical scale. /// The . public AffineTransformBuilder PrependScaleMatrix(SizeF scales) - { - this.PrependMatrix(Matrix3x2Extensions.CreateScale(scales)); - return this; - } + => this.PrependMatrix(Matrix3x2Extensions.CreateScale(scales)); /// /// Appends a scale matrix from the given vector scale. @@ -74,10 +71,7 @@ namespace SixLabors.ImageSharp.Processing /// The horizontal and vertical scale. /// The . public AffineTransformBuilder AppendScaleMatrix(SizeF scales) - { - this.AppendMatrix(Matrix3x2Extensions.CreateScale(scales)); - return this; - } + => this.AppendMatrix(Matrix3x2Extensions.CreateScale(scales)); /// /// Prepends a centered skew matrix from the give angles in degrees. @@ -86,10 +80,7 @@ namespace SixLabors.ImageSharp.Processing /// The Y angle, in degrees. /// The . public AffineTransformBuilder PrependSkewMatrixDegrees(float degreesX, float degreesY) - { - this.PrependMatrix(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); - return this; - } + => this.PrependMatrix(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); /// /// Appends a centered skew matrix from the give angles in degrees. @@ -98,10 +89,7 @@ namespace SixLabors.ImageSharp.Processing /// The Y angle, in degrees. /// The . public AffineTransformBuilder AppendSkewMatrixDegrees(float degreesX, float degreesY) - { - this.AppendMatrix(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); - return this; - } + => this.AppendMatrix(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); /// /// Prepends a translation matrix from the given vector. @@ -109,10 +97,7 @@ namespace SixLabors.ImageSharp.Processing /// The translation position. /// The . public AffineTransformBuilder PrependTranslationMatrix(PointF position) - { - this.PrependMatrix(Matrix3x2Extensions.CreateTranslation(position)); - return this; - } + => this.PrependMatrix(Matrix3x2Extensions.CreateTranslation(position)); /// /// Appends a translation matrix from the given vector. @@ -120,10 +105,7 @@ namespace SixLabors.ImageSharp.Processing /// The translation position. /// The . public AffineTransformBuilder AppendTranslationMatrix(PointF position) - { - this.AppendMatrix(Matrix3x2Extensions.CreateTranslation(position)); - return this; - } + => this.AppendMatrix(Matrix3x2Extensions.CreateTranslation(position)); /// /// Prepends a raw matrix. diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index 529dd56b19..be4c675189 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -20,7 +20,13 @@ namespace SixLabors.ImageSharp.Processing /// Initializes a new instance of the class. /// /// The source image size. - public ProjectiveTransformBuilder(Size sourceSize) => this.Size = sourceSize; + public ProjectiveTransformBuilder(Size sourceSize) + { + Guard.MustBeGreaterThan(sourceSize.Width, 0, nameof(sourceSize)); + Guard.MustBeGreaterThan(sourceSize.Height, 0, nameof(sourceSize)); + + this.Size = sourceSize; + } /// /// Initializes a new instance of the class. @@ -43,10 +49,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount to taper. /// The . public ProjectiveTransformBuilder PrependTaperMatrix(TaperSide side, TaperCorner corner, float fraction) - { - this.PrependMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); - return this; - } + => this.PrependMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); /// /// Appends a matrix that performs a tapering projective transform. @@ -56,10 +59,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount to taper. /// The . public ProjectiveTransformBuilder AppendTaperMatrix(TaperSide side, TaperCorner corner, float fraction) - { - this.AppendMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); - return this; - } + => this.AppendMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); /// /// Prepends a raw matrix. diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs new file mode 100644 index 0000000000..eaa51b1296 --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using SixLabors.ImageSharp.Processing; +using SixLabors.Primitives; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Processing.Transforms +{ + public class AffineTransformBuilderTests + { + [Fact] + public void ConstructorAssignsProperties() + { + var s = new Size(1, 1); + var builder = new AffineTransformBuilder(new Rectangle(Point.Empty, s)); + Assert.Equal(s, builder.Size); + } + + [Fact] + public void ConstructorThrowsInvalid() + { + Assert.Throws(() => + { + var s = new Size(0, 1); + var builder = new AffineTransformBuilder(new Rectangle(Point.Empty, s)); + }); + + Assert.Throws(() => + { + var s = new Size(1, 0); + var builder = new AffineTransformBuilder(new Rectangle(Point.Empty, s)); + }); + } + + [Fact] + public void AppendPrependOpposite() + { + var rectangle = new Rectangle(-1, -1, 3, 3); + var b1 = new AffineTransformBuilder(rectangle); + var b2 = new AffineTransformBuilder(rectangle); + + const float pi = (float)Math.PI; + + // Forwards + b1.AppendRotateMatrixDegrees(pi) + .AppendSkewMatrixDegrees(pi, pi) + .AppendScaleMatrix(new SizeF(pi, pi)) + .AppendTranslationMatrix(new PointF(pi, pi)); + + // Backwards + b2.PrependTranslationMatrix(new PointF(pi, pi)) + .PrependScaleMatrix(new SizeF(pi, pi)) + .PrependSkewMatrixDegrees(pi, pi) + .PrependRotateMatrixDegrees(pi); + + Assert.Equal(b1.BuildMatrix(), b2.BuildMatrix()); + } + + [Fact] + public void BuilderCanClear() + { + var rectangle = new Rectangle(0, 0, 3, 3); + var builder = new AffineTransformBuilder(rectangle); + Matrix3x2 matrix = Matrix3x2.Identity; + matrix.M31 = (float)Math.PI; + + Assert.Equal(Matrix3x2.Identity, builder.BuildMatrix()); + + builder.AppendMatrix(matrix); + Assert.NotEqual(Matrix3x2.Identity, builder.BuildMatrix()); + + builder.Clear(); + Assert.Equal(Matrix3x2.Identity, builder.BuildMatrix()); + } + } +} diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs new file mode 100644 index 0000000000..3dfc42d4f7 --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs @@ -0,0 +1,78 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using SixLabors.ImageSharp.Processing; +using SixLabors.Primitives; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Processing.Transforms +{ + public class ProjectiveTransformBuilderTests + { + [Fact] + public void ConstructorAssignsProperties() + { + var s = new Size(1, 1); + var builder = new ProjectiveTransformBuilder(new Rectangle(Point.Empty, s)); + Assert.Equal(s, builder.Size); + } + + [Fact] + public void ConstructorThrowsInvalid() + { + Assert.Throws(() => + { + var s = new Size(0, 1); + var builder = new ProjectiveTransformBuilder(new Rectangle(Point.Empty, s)); + }); + + Assert.Throws(() => + { + var s = new Size(1, 0); + var builder = new ProjectiveTransformBuilder(new Rectangle(Point.Empty, s)); + }); + } + + [Fact] + public void AppendPrependOpposite() + { + var rectangle = new Rectangle(-1, -1, 3, 3); + var b1 = new ProjectiveTransformBuilder(rectangle); + var b2 = new ProjectiveTransformBuilder(rectangle); + + const float pi = (float)Math.PI; + + Matrix4x4 m4 = Matrix4x4.Identity; + m4.M31 = pi; + + // Forwards + b1.AppendMatrix(m4) + .AppendTaperMatrix(TaperSide.Left, TaperCorner.LeftOrTop, pi); + + // Backwards + b2.PrependTaperMatrix(TaperSide.Left, TaperCorner.LeftOrTop, pi) + .PrependMatrix(m4); + + Assert.Equal(b1.BuildMatrix(), b2.BuildMatrix()); + } + + [Fact] + public void BuilderCanClear() + { + var rectangle = new Rectangle(0, 0, 3, 3); + var builder = new ProjectiveTransformBuilder(rectangle); + Matrix4x4 matrix = Matrix4x4.Identity; + matrix.M31 = (float)Math.PI; + + Assert.Equal(Matrix4x4.Identity, builder.BuildMatrix()); + + builder.AppendMatrix(matrix); + Assert.NotEqual(Matrix4x4.Identity, builder.BuildMatrix()); + + builder.Clear(); + Assert.Equal(Matrix4x4.Identity, builder.BuildMatrix()); + } + } +} From 6558464c7532736d3e4a5cef3eb60ce3332c573e Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Mon, 12 Nov 2018 13:34:17 -0600 Subject: [PATCH 336/381] ImageSharp-762_Aot-compiling: renamed to AotCompilerTools --- src/ImageSharp/Advanced/{AotCompiler.cs => AotCompilerTools.cs} | 2 +- tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/ImageSharp/Advanced/{AotCompiler.cs => AotCompilerTools.cs} (99%) diff --git a/src/ImageSharp/Advanced/AotCompiler.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs similarity index 99% rename from src/ImageSharp/Advanced/AotCompiler.cs rename to src/ImageSharp/Advanced/AotCompilerTools.cs index 406c162ad5..9e7624480d 100644 --- a/src/ImageSharp/Advanced/AotCompiler.cs +++ b/src/ImageSharp/Advanced/AotCompilerTools.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Advanced /// these are caused because not every possible generic instantiation can be determined up front at compile time. /// The Aot Compiler is designed to overcome the limitations of this compiler. /// - public static class AotCompiler + public static class AotCompilerTools { /// /// Seeds the compiler using the given pixel format. diff --git a/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs b/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs index 3d6faa27ec..5c1dd4bb08 100644 --- a/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs +++ b/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.Advanced [Fact] public void AotCompiler_NoExceptions() { - AotCompiler.Seed(); + AotCompilerTools.Seed(); } } } From 6a81923ab7f57d7d947f826de1ef426bec5806ca Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 12 Nov 2018 20:34:37 +0000 Subject: [PATCH 337/381] Tighten up coverage on new AotCompilerTools --- tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs b/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs index 5c1dd4bb08..f6397dbd09 100644 --- a/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs +++ b/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs @@ -10,9 +10,6 @@ namespace SixLabors.ImageSharp.Tests.Advanced public class AotCompilerTests { [Fact] - public void AotCompiler_NoExceptions() - { - AotCompilerTools.Seed(); - } + public void AotCompiler_NoExceptions() => AotCompilerTools.Seed(); } } From 1c258dcae42f959e1fcf0cd355f3c2aad63a5bf6 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 13 Nov 2018 09:38:57 +0000 Subject: [PATCH 338/381] Update tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs --- .../Processing/Transforms/AffineTransformTests.cs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index 15b4500bb2..3d7fba2c19 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -207,21 +207,6 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms } } - private Matrix3x2 MakeManuallyCenteredMatrix(float angleDeg, float s, Image image) - where TPixel : struct, IPixel - { - Matrix3x2 rotate = Matrix3x2Extensions.CreateRotationDegrees(angleDeg); - Vector2 toCenter = 0.5f * new Vector2(image.Width, image.Height); - var translate = Matrix3x2.CreateTranslation(-toCenter); - var translateBack = Matrix3x2.CreateTranslation(toCenter); - var scale = Matrix3x2.CreateScale(s); - - Matrix3x2 m = translate * rotate * scale * translateBack; - - this.PrintMatrix(m); - return m; - } - private static IResampler GetResampler(string name) { PropertyInfo property = typeof(KnownResamplers).GetTypeInfo().GetProperty(name); From 0ac969a711ed043f0586a961b12b4451dc29cbe2 Mon Sep 17 00:00:00 2001 From: Curtis Wensley Date: Thu, 1 Nov 2018 16:25:55 -0700 Subject: [PATCH 339/381] Optimize filling a region with a solid brush when antialias is off --- .../Processors/Drawing/FillRegionProcessor.cs | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs index 1dc63efa27..170e3d34f2 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs @@ -3,7 +3,7 @@ using System; using System.Buffers; - +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; @@ -168,17 +168,31 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing { if (!this.Options.Antialias) { + bool hasOnes = false; + bool hasZeros = false; for (int x = 0; x < scanlineWidth; x++) { if (scanline[x] >= 0.5) { scanline[x] = 1; + hasOnes = true; } else { scanline[x] = 0; + hasZeros = true; } } + + if (hasOnes != hasZeros && this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush)) + { + if (hasOnes) + { + source.GetPixelRowSpan(y).Slice(minX, scanlineWidth).Fill(solidBrush.Color); + } + + continue; + } } applicator.Apply(scanline, minX, y); @@ -187,5 +201,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing } } } + + private bool IsSolidBrushWithoutBlending(out SolidBrush solidBrush) + { + solidBrush = this.Brush as SolidBrush; + + if (solidBrush == null) + { + return false; + } + + return this.Options.IsOpaqueColorWithoutBlending(solidBrush.Color); + } } } \ No newline at end of file From 8073404c7773d5808f2372d0c72fe035bc78bb9e Mon Sep 17 00:00:00 2001 From: Curtis Wensley Date: Thu, 15 Nov 2018 08:55:22 -0800 Subject: [PATCH 340/381] Check for solid brush outside of loops --- .../Processing/Processors/Drawing/FillRegionProcessor.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs index 170e3d34f2..550c021caa 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs @@ -107,6 +107,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing Span buffer = bBuffer.GetSpan(); Span scanline = bScanline.GetSpan(); + bool isSolidBrushWithoutBlending = this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush); + for (int y = minY; y < maxY; y++) { if (scanlineDirty) @@ -184,7 +186,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing } } - if (hasOnes != hasZeros && this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush)) + if (isSolidBrushWithoutBlending && hasOnes != hasZeros) { if (hasOnes) { From f79f1894a342dae48629c5ea756185f7572af313 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 22 Nov 2018 17:09:48 +0000 Subject: [PATCH 341/381] Reduce allocatoins, check bit depth and rename. --- src/ImageSharp/Formats/Png/PngChunkType.cs | 4 +- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 6 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 107 ++++++++---------- .../Formats/Png/PngChunkTypeTests.cs | 2 +- .../Formats/Png/PngDecoderTests.Chunks.cs | 2 +- 5 files changed, 56 insertions(+), 65 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngChunkType.cs b/src/ImageSharp/Formats/Png/PngChunkType.cs index 7654c17014..1b251a5748 100644 --- a/src/ImageSharp/Formats/Png/PngChunkType.cs +++ b/src/ImageSharp/Formats/Png/PngChunkType.cs @@ -56,10 +56,10 @@ namespace SixLabors.ImageSharp.Formats.Png Text = 0x74455874U, /// - /// This chunk specifies that the image uses simple transparency: + /// The tRNS 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). /// - PaletteAlpha = 0x74524E53U + Transparency = 0x74524E53U } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index c446184d80..9ffac5e626 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -197,7 +197,7 @@ namespace SixLabors.ImageSharp.Formats.Png Buffer.BlockCopy(chunk.Data.Array, 0, pal, 0, chunk.Length); this.palette = pal; break; - case PngChunkType.PaletteAlpha: + case PngChunkType.Transparency: byte[] alpha = new byte[chunk.Length]; Buffer.BlockCopy(chunk.Data.Array, 0, alpha, 0, chunk.Length); this.paletteAlpha = alpha; @@ -306,9 +306,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/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 532e6f7471..8a31aaf51b 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -292,7 +292,7 @@ namespace SixLabors.ImageSharp.Formats.Png if (pngMetaData.HasTrans) { - this.WriteTransparencyMarkers(stream, pngMetaData); + this.WriteTransparencyChunk(stream, pngMetaData); } this.WritePhysicalChunk(stream, metaData); @@ -305,52 +305,6 @@ namespace SixLabors.ImageSharp.Formats.Png quantized?.Dispose(); } - /// - /// Writes the transparency markers to the stream - /// - /// The containing image data. - /// The image meta data. - private void WriteTransparencyMarkers(Stream stream, PngMetaData pngMetaData) - { - if (pngMetaData.ColorType == PngColorType.Rgb) - { - if (pngMetaData.TransparentRgb48 != null) - { - var r = BitConverter.GetBytes(pngMetaData.TransparentRgb48.Value.R); - var g = BitConverter.GetBytes(pngMetaData.TransparentRgb48.Value.R); - var b = BitConverter.GetBytes(pngMetaData.TransparentRgb48.Value.B); - - var alphaArray = r.Concat(g).Concat(b).ToArray(); - - this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); - } - else if (pngMetaData.TransparentRgb24 != null) - { - var alphaArray = new byte[6]; - alphaArray[1] = pngMetaData.TransparentRgb24.Value.R; - alphaArray[3] = pngMetaData.TransparentRgb24.Value.G; - alphaArray[5] = pngMetaData.TransparentRgb24.Value.B; - this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); - } - } - else if (pngMetaData.ColorType == PngColorType.Grayscale) - { - if (pngMetaData.TransparentGray16 != null) - { - var alphaArray = BitConverter.GetBytes(pngMetaData.TransparentGray16.Value.PackedValue); - - this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); - } - else if (pngMetaData.TransparentGray8 != null) - { - var alphaArray = new byte[2]; - alphaArray[1] = pngMetaData.TransparentGray8.Value.PackedValue; - - this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); - } - } - } - /// public void Dispose() { @@ -377,7 +331,6 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.pngColorType.Equals(PngColorType.Grayscale)) { - // TODO: Research and add support for grayscale plus tRNS if (this.use16Bit) { // 16 bit grayscale @@ -752,7 +705,7 @@ namespace SixLabors.ImageSharp.Formats.Png // Write the transparency data if (anyAlpha) { - this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaTable.Array, 0, paletteLength); + this.WriteChunk(stream, PngChunkType.Transparency, alphaTable.Array, 0, paletteLength); } } } @@ -800,6 +753,52 @@ namespace SixLabors.ImageSharp.Formats.Png } } + /// + /// Writes the transparency chunk to the stream + /// + /// The containing image data. + /// The image meta data. + private void WriteTransparencyChunk(Stream stream, PngMetaData pngMetaData) + { + if (pngMetaData.ColorType.Equals(PngColorType.Rgb)) + { + Span alpha = this.buffer.AsSpan(); + if (pngMetaData.TransparentRgb48.HasValue && this.use16Bit) + { + Rgb48 rgb = pngMetaData.TransparentRgb48.Value; + BinaryPrimitives.WriteUInt16LittleEndian(alpha, rgb.R); + BinaryPrimitives.WriteUInt16LittleEndian(alpha.Slice(2, 2), rgb.G); + BinaryPrimitives.WriteUInt16LittleEndian(alpha.Slice(4, 2), rgb.B); + + this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 6); + } + else if (pngMetaData.TransparentRgb24.HasValue) + { + alpha.Clear(); + Rgb24 rgb = pngMetaData.TransparentRgb24.Value; + alpha[1] = rgb.R; + alpha[3] = rgb.G; + alpha[5] = rgb.B; + this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 6); + } + } + else if (pngMetaData.ColorType.Equals(PngColorType.Grayscale)) + { + Span alpha = this.buffer.AsSpan(); + if (pngMetaData.TransparentGray16.HasValue && this.bitDepth == 16) + { + BinaryPrimitives.WriteUInt16LittleEndian(alpha, pngMetaData.TransparentGray16.Value.PackedValue); + this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 2); + } + else if (pngMetaData.TransparentGray8.HasValue) + { + alpha.Clear(); + alpha[1] = pngMetaData.TransparentGray8.Value.PackedValue; + this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 2); + } + } + } + /// /// Writes the pixel information to the stream. /// @@ -894,10 +893,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. @@ -905,10 +901,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/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs index e4cd06ab1b..894d902b78 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png Assert.Equal(PngChunkType.Palette, GetType("PLTE")); Assert.Equal(PngChunkType.Data, GetType("IDAT")); Assert.Equal(PngChunkType.End, GetType("IEND")); - Assert.Equal(PngChunkType.PaletteAlpha, GetType("tRNS")); + Assert.Equal(PngChunkType.Transparency, GetType("tRNS")); Assert.Equal(PngChunkType.Text, GetType("tEXt")); Assert.Equal(PngChunkType.Gamma, GetType("gAMA")); Assert.Equal(PngChunkType.Physical, GetType("pHYs")); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs index 2a7d696164..6a0119f0f1 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png [Theory] [InlineData((uint)PngChunkType.Gamma)] // gAMA - [InlineData((uint)PngChunkType.PaletteAlpha)] // tRNS + [InlineData((uint)PngChunkType.Transparency)] // tRNS [InlineData((uint)PngChunkType.Physical)] // pHYs: It's ok to test physical as we don't throw for duplicate chunks. //[InlineData(PngChunkTypes.Text)] //TODO: Figure out how to test this public void Decode_IncorrectCRCForNonCriticalChunk_ExceptionIsThrown(uint chunkType) From ead17fd0179c98b99b3212b9213bcefbf9335e89 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 22 Nov 2018 17:12:43 +0000 Subject: [PATCH 342/381] Use existing field --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 8a31aaf51b..bb800c8a48 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -785,7 +785,7 @@ namespace SixLabors.ImageSharp.Formats.Png else if (pngMetaData.ColorType.Equals(PngColorType.Grayscale)) { Span alpha = this.buffer.AsSpan(); - if (pngMetaData.TransparentGray16.HasValue && this.bitDepth == 16) + if (pngMetaData.TransparentGray16.HasValue && this.use16Bit) { BinaryPrimitives.WriteUInt16LittleEndian(alpha, pngMetaData.TransparentGray16.Value.PackedValue); this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 2); From 68496170654216571d54261d3f7074b8e9194a45 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 23 Nov 2018 12:25:05 +0000 Subject: [PATCH 343/381] Fix trns preservation and add tests --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 11 ++- src/ImageSharp/Formats/Png/PngMetaData.cs | 5 ++ .../Formats/Png/PngEncoderTests.cs | 67 ++++++++++++++++++ tests/ImageSharp.Tests/TestImages.cs | 3 + tests/Images/Input/Png/gray-2-tRNS.png | Bin 0 -> 265 bytes tests/Images/Input/Png/gray-4-tRNS.png | Bin 0 -> 267 bytes tests/Images/Input/Png/gray-8-tRNS.png | Bin 0 -> 267 bytes 7 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 tests/Images/Input/Png/gray-2-tRNS.png create mode 100644 tests/Images/Input/Png/gray-4-tRNS.png create mode 100644 tests/Images/Input/Png/gray-8-tRNS.png diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index bb800c8a48..292de007ca 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -760,9 +760,9 @@ namespace SixLabors.ImageSharp.Formats.Png /// The image meta data. private void WriteTransparencyChunk(Stream stream, PngMetaData pngMetaData) { + Span alpha = this.chunkDataBuffer.AsSpan(); if (pngMetaData.ColorType.Equals(PngColorType.Rgb)) { - Span alpha = this.buffer.AsSpan(); if (pngMetaData.TransparentRgb48.HasValue && this.use16Bit) { Rgb48 rgb = pngMetaData.TransparentRgb48.Value; @@ -770,7 +770,7 @@ namespace SixLabors.ImageSharp.Formats.Png BinaryPrimitives.WriteUInt16LittleEndian(alpha.Slice(2, 2), rgb.G); BinaryPrimitives.WriteUInt16LittleEndian(alpha.Slice(4, 2), rgb.B); - this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 6); + this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 6); } else if (pngMetaData.TransparentRgb24.HasValue) { @@ -779,22 +779,21 @@ namespace SixLabors.ImageSharp.Formats.Png alpha[1] = rgb.R; alpha[3] = rgb.G; alpha[5] = rgb.B; - this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 6); + this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 6); } } else if (pngMetaData.ColorType.Equals(PngColorType.Grayscale)) { - Span alpha = this.buffer.AsSpan(); if (pngMetaData.TransparentGray16.HasValue && this.use16Bit) { BinaryPrimitives.WriteUInt16LittleEndian(alpha, pngMetaData.TransparentGray16.Value.PackedValue); - this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 2); + this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 2); } else if (pngMetaData.TransparentGray8.HasValue) { alpha.Clear(); alpha[1] = pngMetaData.TransparentGray8.Value.PackedValue; - this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 2); + this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 2); } } } diff --git a/src/ImageSharp/Formats/Png/PngMetaData.cs b/src/ImageSharp/Formats/Png/PngMetaData.cs index 6a293f770c..d5ab3d2554 100644 --- a/src/ImageSharp/Formats/Png/PngMetaData.cs +++ b/src/ImageSharp/Formats/Png/PngMetaData.cs @@ -26,6 +26,11 @@ namespace SixLabors.ImageSharp.Formats.Png this.BitDepth = other.BitDepth; this.ColorType = other.ColorType; this.Gamma = other.Gamma; + this.HasTrans = other.HasTrans; + this.TransparentGray8 = other.TransparentGray8; + this.TransparentGray16 = other.TransparentGray16; + this.TransparentRgb24 = other.TransparentRgb24; + this.TransparentRgb48 = other.TransparentRgb48; } /// diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 5d328db361..9079b15fb0 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -25,6 +25,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png { TestImages.Png.Bpp1, PngBitDepth.Bit1 } }; + public static readonly TheoryData PngTrnsFiles = + new TheoryData + { + { TestImages.Png.Gray1BitTrans, PngBitDepth.Bit1, PngColorType.Grayscale }, + { TestImages.Png.Gray2BitTrans, PngBitDepth.Bit2, PngColorType.Grayscale }, + { TestImages.Png.Gray4BitTrans, PngBitDepth.Bit4, PngColorType.Grayscale }, + { TestImages.Png.Gray8BitTrans, PngBitDepth.Bit8, PngColorType.Grayscale }, + { TestImages.Png.GrayTrns16BitInterlaced, PngBitDepth.Bit16, PngColorType.Grayscale }, + { TestImages.Png.Rgb24BppTrans, PngBitDepth.Bit8, PngColorType.Rgb }, + { TestImages.Png.Rgb48BppTrans, PngBitDepth.Bit16, PngColorType.Rgb } + }; + /// /// All types except Palette /// @@ -249,6 +261,61 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } } + [Theory] + [MemberData(nameof(PngTrnsFiles))] + public void Encode_PreserveTrns(string imagePath, PngBitDepth pngBitDepth, PngColorType pngColorType) + { + var options = new PngEncoder(); + + var testFile = TestFile.Create(imagePath); + using (Image input = testFile.CreateImage()) + { + PngMetaData inMeta = input.MetaData.GetFormatMetaData(PngFormat.Instance); + Assert.True(inMeta.HasTrans); + + using (var memStream = new MemoryStream()) + { + input.Save(memStream, options); + memStream.Position = 0; + using (var output = Image.Load(memStream)) + { + PngMetaData outMeta = output.MetaData.GetFormatMetaData(PngFormat.Instance); + Assert.True(outMeta.HasTrans); + + switch (pngColorType) + { + case PngColorType.Grayscale: + if (pngBitDepth.Equals(PngBitDepth.Bit16)) + { + Assert.True(outMeta.TransparentGray16.HasValue); + Assert.Equal(inMeta.TransparentGray16, outMeta.TransparentGray16); + } + else + { + Assert.True(outMeta.TransparentGray8.HasValue); + Assert.Equal(inMeta.TransparentGray8, outMeta.TransparentGray8); + } + + break; + case PngColorType.Rgb: + if (pngBitDepth.Equals(PngBitDepth.Bit16)) + { + Assert.True(outMeta.TransparentRgb48.HasValue); + Assert.Equal(inMeta.TransparentRgb48, outMeta.TransparentRgb48); + } + else + { + Assert.True(outMeta.TransparentRgb24.HasValue); + Assert.Equal(inMeta.TransparentRgb24, outMeta.TransparentRgb24); + } + + break; + } + } + } + } + } + private static void TestPngEncoderCore( TestImageProvider provider, PngColorType pngColorType, diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 8da458e520..1144a3f7c0 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -46,6 +46,9 @@ namespace SixLabors.ImageSharp.Tests public const string PDSrc = "Png/pd-source.png"; public const string PDDest = "Png/pd-dest.png"; public const string Gray1BitTrans = "Png/gray-1-trns.png"; + public const string Gray2BitTrans = "Png/gray-2-tRNS.png"; + public const string Gray4BitTrans = "Png/gray-4-tRNS.png"; + public const string Gray8BitTrans = "Png/gray-8-tRNS.png"; // Filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html public const string Filter0 = "Png/filter0.png"; diff --git a/tests/Images/Input/Png/gray-2-tRNS.png b/tests/Images/Input/Png/gray-2-tRNS.png new file mode 100644 index 0000000000000000000000000000000000000000..8e04cb5020cc1ecf62544cb32d5b79c80db9eb55 GIT binary patch literal 265 zcmeAS@N?(olHy`uVBq!ia0vp^EI`c21SA-yJ@?oEq?k&A{DK)68K?YR2juCLxJHyX z=ND8KWu|A8FsxKCGB7mO0TQMPUile$3eKf@d6{|X8Hu?HPWk0IsYSIV#s7f%N-{$t zN_;YtQ}c>}(hQ6Ysd)?x9M^SweEFIc1X|aBdc-KRJ9m18V9RtbC7#BO-2Ur1W9#j; zlez9mBy!#Etjcre>X=olwIZjW_ui%cf?1oV^|fysu_zijiZ`$`Yrw=Fz( zYoAeHvWEEVQdfX$D4y)I0_Tj_bNTzI@FJ0MksZvXY1vGw-a z$z1m&61i@7R^_>KbOT9H%Gd+$_Bo*Zy%#K^eU$*(yeWi!*+ZLX? zwa=(8SwnpGsmmvLjg7RLZp>J#2DG2Y)5S4_<9c#R2+&W=ml!^t%;`7}6ld^s^>bP0 Hl+XkKeMDTy literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Png/gray-8-tRNS.png b/tests/Images/Input/Png/gray-8-tRNS.png new file mode 100644 index 0000000000000000000000000000000000000000..842245f1d9f192857edd85f43f2d8d6ca8874c01 GIT binary patch literal 267 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K57&$`wkAjMP?KCsyuhDj#;%@D{=~Y?_KIIn6-IYU;E~gq@uio*>TJG%QoM-uk`SJ+ro3V z_8IjhYlzQ2b@>FZv5{8OjTvjzfcEovx;TbNTux4rdC0)f)WpbSSo>uLP@KWj)z4*} HQ$iB}V~<+M literal 0 HcmV?d00001 From da50180e1c7a2aa34d94d578824deec4ea3e6b0a Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 25 Nov 2018 22:52:47 +0100 Subject: [PATCH 344/381] add more tests --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 15 +- .../Processing/AffineTransformBuilder.cs | 35 ++-- .../Processors/Transforms/TransformUtils.cs | 11 ++ .../Transforms/AffineTransformBuilderTests.cs | 67 +++----- .../Transforms/TransformBuilderTestBase.cs | 151 ++++++++++++++++++ .../TestUtilities/ApproximateFloatComparer.cs | 13 +- 6 files changed, 234 insertions(+), 58 deletions(-) create mode 100644 tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index f07ccb03b4..45556741e6 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -22,7 +22,8 @@ namespace SixLabors.ImageSharp /// The blue component. /// The . [MethodImpl(InliningOptions.ShortMethod)] - public static byte Get8BitBT709Luminance(byte r, byte g, byte b) => (byte)((r * .2126F) + (g * .7152F) + (b * .0722F) + 0.5f); + public static byte Get8BitBT709Luminance(byte r, byte g, byte b) => + (byte)((r * .2126F) + (g * .7152F) + (b * .0722F) + 0.5f); /// /// Gets the luminance from the rgb components using the formula as specified by ITU-R Recommendation BT.709. @@ -32,7 +33,8 @@ namespace SixLabors.ImageSharp /// The blue component. /// The . [MethodImpl(InliningOptions.ShortMethod)] - public static ushort Get16BitBT709Luminance(ushort r, ushort g, ushort b) => (ushort)((r * .2126F) + (g * .7152F) + (b * .0722F)); + public static ushort Get16BitBT709Luminance(ushort r, ushort g, ushort b) => + (ushort)((r * .2126F) + (g * .7152F) + (b * .0722F)); /// /// Scales a value from a 16 bit to it's 8 bit equivalent. @@ -128,6 +130,15 @@ namespace SixLabors.ImageSharp return x & (m - 1); } + /// + /// Converts degrees to radians + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static float ToRadian(float degrees) + { + return degrees * ((float)Math.PI / 180f); + } + /// /// Returns the absolute value of a 32-bit signed integer. Uses bit shifting to speed up the operation. /// diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index 003249d6ed..4d798f4396 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -14,18 +14,15 @@ namespace SixLabors.ImageSharp.Processing public class AffineTransformBuilder { private readonly List matrices = new List(); - private Rectangle rectangle; + private readonly Rectangle rectangle; /// /// Initializes a new instance of the class. /// /// The source image size. public AffineTransformBuilder(Size sourceSize) + : this(new Rectangle(Point.Empty, sourceSize)) { - Guard.MustBeGreaterThan(sourceSize.Width, 0, nameof(sourceSize)); - Guard.MustBeGreaterThan(sourceSize.Height, 0, nameof(sourceSize)); - - this.Size = sourceSize; } /// @@ -33,13 +30,17 @@ namespace SixLabors.ImageSharp.Processing /// /// The source rectangle. public AffineTransformBuilder(Rectangle sourceRectangle) - : this(sourceRectangle.Size) - => this.rectangle = sourceRectangle; + { + Guard.MustBeGreaterThan(sourceRectangle.Width, 0, nameof(sourceRectangle)); + Guard.MustBeGreaterThan(sourceRectangle.Height, 0, nameof(sourceRectangle)); + + this.rectangle = sourceRectangle; + } /// /// Gets the source image size. /// - internal Size Size { get; } + internal Size Size => this.rectangle.Size; /// /// Prepends a centered rotation matrix using the given rotation in degrees. @@ -49,13 +50,29 @@ namespace SixLabors.ImageSharp.Processing public AffineTransformBuilder PrependRotateMatrixDegrees(float degrees) => this.PrependMatrix(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); + /// + /// Prepends a centered rotation matrix using the given rotation in radians. + /// + /// The amount of rotation, in radians. + /// The . + public AffineTransformBuilder PrependRotateMatrixRadians(float radians) + => this.PrependMatrix(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); + /// /// Appends a centered rotation matrix using the given rotation in degrees. /// /// The amount of rotation, in degrees. /// The . public AffineTransformBuilder AppendRotateMatrixDegrees(float degrees) - => this.AppendMatrix(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); + => this.AppendRotateMatrixRadians(ImageMaths.ToRadian(degrees)); + + /// + /// Appends a centered rotation matrix using the given rotation in radians. + /// + /// The amount of rotation, in radians. + /// The . + public AffineTransformBuilder AppendRotateMatrixRadians(float radians) + => this.AppendMatrix(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); /// /// Prepends a scale matrix from the given vector scale. diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs index f561d3513f..6cef38f8fe 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs @@ -23,6 +23,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms new Rectangle(Point.Empty, size), Matrix3x2Extensions.CreateRotationDegrees(degrees, PointF.Empty)); + /// + /// Creates a centered rotation matrix using the given rotation in radians and the source size. + /// + /// The amount of rotation, in radians. + /// The source image size. + /// The . + public static Matrix3x2 CreateRotationMatrixRadians(float radians, Size size) + => CreateCenteredTransformMatrix( + new Rectangle(Point.Empty, size), + Matrix3x2Extensions.CreateRotation(radians, PointF.Empty)); + /// /// Creates a centered skew matrix from the give angles in degrees and the source size. /// diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs index eaa51b1296..1b4caee14f 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs @@ -4,12 +4,13 @@ using System; using System.Numerics; using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.Primitives; using Xunit; namespace SixLabors.ImageSharp.Tests.Processing.Transforms { - public class AffineTransformBuilderTests + public class AffineTransformBuilderTests : TransformBuilderTestBase { [Fact] public void ConstructorAssignsProperties() @@ -23,57 +24,33 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms public void ConstructorThrowsInvalid() { Assert.Throws(() => - { - var s = new Size(0, 1); - var builder = new AffineTransformBuilder(new Rectangle(Point.Empty, s)); - }); + { + var s = new Size(0, 1); + var builder = new AffineTransformBuilder(new Rectangle(Point.Empty, s)); + }); Assert.Throws(() => - { - var s = new Size(1, 0); - var builder = new AffineTransformBuilder(new Rectangle(Point.Empty, s)); - }); + { + var s = new Size(1, 0); + var builder = new AffineTransformBuilder(new Rectangle(Point.Empty, s)); + }); } - [Fact] - public void AppendPrependOpposite() - { - var rectangle = new Rectangle(-1, -1, 3, 3); - var b1 = new AffineTransformBuilder(rectangle); - var b2 = new AffineTransformBuilder(rectangle); - - const float pi = (float)Math.PI; - - // Forwards - b1.AppendRotateMatrixDegrees(pi) - .AppendSkewMatrixDegrees(pi, pi) - .AppendScaleMatrix(new SizeF(pi, pi)) - .AppendTranslationMatrix(new PointF(pi, pi)); - - // Backwards - b2.PrependTranslationMatrix(new PointF(pi, pi)) - .PrependScaleMatrix(new SizeF(pi, pi)) - .PrependSkewMatrixDegrees(pi, pi) - .PrependRotateMatrixDegrees(pi); + protected override void AppendTranslation(AffineTransformBuilder builder, PointF translate) => builder.AppendTranslationMatrix(translate); + protected override void AppendScale(AffineTransformBuilder builder, SizeF scale) => builder.AppendScaleMatrix(scale); + protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendRotateMatrixRadians(radians); - Assert.Equal(b1.BuildMatrix(), b2.BuildMatrix()); - } + protected override void PrependTranslation(AffineTransformBuilder builder, PointF translate) => builder.PrependTranslationMatrix(translate); + protected override void PrependScale(AffineTransformBuilder builder, SizeF scale) => builder.PrependScaleMatrix(scale); + protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) => builder.PrependRotateMatrixRadians(radians); - [Fact] - public void BuilderCanClear() + protected override Vector2 Execute( + AffineTransformBuilder builder, + Rectangle rectangle, + Vector2 sourcePoint) { - var rectangle = new Rectangle(0, 0, 3, 3); - var builder = new AffineTransformBuilder(rectangle); - Matrix3x2 matrix = Matrix3x2.Identity; - matrix.M31 = (float)Math.PI; - - Assert.Equal(Matrix3x2.Identity, builder.BuildMatrix()); - - builder.AppendMatrix(matrix); - Assert.NotEqual(Matrix3x2.Identity, builder.BuildMatrix()); - - builder.Clear(); - Assert.Equal(Matrix3x2.Identity, builder.BuildMatrix()); + Matrix3x2 matrix = builder.BuildMatrix(); + return Vector2.Transform(sourcePoint, matrix); } } } diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs new file mode 100644 index 0000000000..d109387cc4 --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs @@ -0,0 +1,151 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; + +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Processors.Transforms; +using SixLabors.Primitives; + +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Processing.Transforms +{ + public abstract class TransformBuilderTestBase + { + private static readonly ApproximateFloatComparer Comparer = new ApproximateFloatComparer(1e-6f); + + public static readonly TheoryData ScaleTranslate_Data = + new TheoryData + { + // scale, translate, source, expectedDest + + { Vector2.One, Vector2.Zero, Vector2.Zero, Vector2.Zero }, + { Vector2.One, Vector2.Zero, new Vector2(10, 20), new Vector2(10, 20) }, + { Vector2.One, new Vector2(3, 1), new Vector2(10, 20), new Vector2(13, 21) }, + { new Vector2(2, 0.5f), new Vector2(3, 1), new Vector2(10, 20), new Vector2(23, 11) }, + }; + + [Theory] + [MemberData(nameof(ScaleTranslate_Data))] + public void _1Scale_2Translate(Vector2 scale, Vector2 translate, Vector2 source, Vector2 expectedDest) + { + // These operations should be size-agnostic: + var size = new Size(123, 321); + TBuilder builder = this.CreateBuilder(size); + + this.AppendScale(builder, new SizeF(scale)); + this.AppendTranslation(builder, translate); + + Vector2 actualDest = this.Execute(builder, new Rectangle(Point.Empty, size), source); + Assert.True(Comparer.Equals(expectedDest, actualDest)); + } + + public static readonly TheoryData TranslateScale_Data = + new TheoryData + { + // translate, scale, source, expectedDest + + { Vector2.Zero, Vector2.One, Vector2.Zero, Vector2.Zero }, + { Vector2.Zero, Vector2.One, new Vector2(10, 20), new Vector2(10, 20) }, + { new Vector2(3, 1), new Vector2(2, 0.5f), new Vector2(10, 20), new Vector2(26, 10.5f) }, + }; + + [Theory] + [MemberData(nameof(TranslateScale_Data))] + public void _1Translate_2Scale(Vector2 translate, Vector2 scale, Vector2 source, Vector2 expectedDest) + { + // Translate ans scale are size-agnostic: + var size = new Size(456, 432); + TBuilder builder = this.CreateBuilder(size); + + this.AppendTranslation(builder, translate); + this.AppendScale(builder, new SizeF(scale)); + + Vector2 actualDest = this.Execute(builder, new Rectangle(Point.Empty, size), source); + Assert.Equal(expectedDest, actualDest, Comparer); + } + + [Theory] + [InlineData(10, 20)] + [InlineData(-20, 10)] + public void LocationOffsetIsPrepended(int locationX, int locationY) + { + var rectangle = new Rectangle(locationX, locationY, 10, 10); + TBuilder builder = this.CreateBuilder(rectangle); + + this.AppendScale(builder, new SizeF(2, 2)); + + Vector2 actual = this.Execute(builder, rectangle, Vector2.One); + Vector2 expected = new Vector2(-locationX + 1, -locationY + 1) * 2; + + Assert.Equal(actual, expected, Comparer); + } + + [Theory] + [InlineData(200, 100, 10, 42, 84)] + [InlineData(200, 100, 100, 42, 84)] + [InlineData(100, 200, -10, 42, 84)] + public void RotateDegrees_ShouldCreateCenteredMatrix(int width, int height, float deg, float x, float y) + { + var size = new Size(width, height); + TBuilder builder = this.CreateBuilder(size); + + this.AppendRotationDegrees(builder, deg); + + // TODO: We should also test CreateRotationMatrixDegrees() (and all TransformUtils stuff!) for correctness + Matrix3x2 matrix = TransformUtils.CreateRotationMatrixDegrees(deg, size); + + var position = new Vector2(x, y); + var expected = Vector2.Transform(position, matrix); + Vector2 actual = this.Execute(builder, new Rectangle(Point.Empty, size), position); + + Assert.Equal(actual, expected, Comparer); + } + + [Fact] + public void AppendPrependOpposite() + { + var rectangle = new Rectangle(-1, -1, 3, 3); + TBuilder b1 = this.CreateBuilder(rectangle); + TBuilder b2 = this.CreateBuilder(rectangle); + + const float pi = (float)Math.PI; + + // Forwards + this.AppendRotationRadians(b1, pi); + this.AppendScale(b1, new SizeF(2, 0.5f)); + this.AppendTranslation(b1, new PointF(123, 321)); + + // Backwards + this.PrependTranslation(b2, new PointF(123, 321)); + this.PrependScale(b2, new SizeF(2, 0.5f)); + this.PrependRotationRadians(b2, pi); + + Vector2 p1 = this.Execute(b1, rectangle, new Vector2(32, 65)); + Vector2 p2 = this.Execute(b2, rectangle, new Vector2(32, 65)); + + Assert.Equal(p1, p2, Comparer); + } + + protected TBuilder CreateBuilder(Size size) => this.CreateBuilder(new Rectangle(Point.Empty, size)); + + protected virtual TBuilder CreateBuilder(Rectangle rectangle) => (TBuilder)Activator.CreateInstance(typeof(TBuilder), rectangle); + + protected abstract void AppendTranslation(TBuilder builder, PointF translate); + protected abstract void AppendScale(TBuilder builder, SizeF scale); + protected abstract void AppendRotationRadians(TBuilder builder, float radians); + + protected abstract void PrependTranslation(TBuilder builder, PointF translate); + protected abstract void PrependScale(TBuilder builder, SizeF scale); + protected abstract void PrependRotationRadians(TBuilder builder, float radians); + + protected virtual void AppendRotationDegrees(TBuilder builder, float degrees) => + this.AppendRotationRadians(builder, ImageMaths.ToRadian(degrees)); + + protected abstract Vector2 Execute(TBuilder builder, Rectangle rectangle, Vector2 sourcePoint); + + private static float Sqrt(float a) => (float)Math.Sqrt(a); + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs index 854e57d8f5..47ca6cccb2 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs @@ -11,7 +11,8 @@ namespace SixLabors.ImageSharp.Tests /// internal readonly struct ApproximateFloatComparer : IEqualityComparer, - IEqualityComparer + IEqualityComparer, + IEqualityComparer { private readonly float Epsilon; @@ -33,9 +34,17 @@ namespace SixLabors.ImageSharp.Tests public int GetHashCode(float obj) => obj.GetHashCode(); /// - 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 bool Equals(Vector4 a, Vector4 b) => this.Equals(a.X, b.X) && this.Equals(a.Y, b.Y) && this.Equals(a.Z, b.Z) && this.Equals(a.W, b.W); /// public int GetHashCode(Vector4 obj) => obj.GetHashCode(); + + /// + public bool Equals(Vector2 a, Vector2 b) => this.Equals(a.X, b.X) && this.Equals(a.Y, b.Y); + + public int GetHashCode(Vector2 obj) + { + throw new System.NotImplementedException(); + } } } \ No newline at end of file From cc2589f88e7887127b19303a19ad5ae0974cb013 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 25 Nov 2018 23:07:50 +0100 Subject: [PATCH 345/381] rename methods + extend API --- .../Processing/AffineTransformBuilder.cs | 78 +++++++++++++++---- .../ImageSharp.Tests/Drawing/DrawImageTest.cs | 6 +- .../Transforms/AffineTransformBuilderTests.cs | 12 +-- .../Transforms/AffineTransformTests.cs | 20 ++--- 4 files changed, 82 insertions(+), 34 deletions(-) diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index 4d798f4396..1620b72234 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Processing /// /// The amount of rotation, in degrees. /// The . - public AffineTransformBuilder PrependRotateMatrixDegrees(float degrees) + public AffineTransformBuilder PrependRotationDegrees(float degrees) => this.PrependMatrix(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); /// @@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Processing /// /// The amount of rotation, in radians. /// The . - public AffineTransformBuilder PrependRotateMatrixRadians(float radians) + public AffineTransformBuilder PrependRotationRadians(float radians) => this.PrependMatrix(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); /// @@ -63,32 +63,64 @@ namespace SixLabors.ImageSharp.Processing /// /// The amount of rotation, in degrees. /// The . - public AffineTransformBuilder AppendRotateMatrixDegrees(float degrees) - => this.AppendRotateMatrixRadians(ImageMaths.ToRadian(degrees)); + public AffineTransformBuilder AppendRotationDegrees(float degrees) + => this.AppendRotationRadians(ImageMaths.ToRadian(degrees)); /// /// Appends a centered rotation matrix using the given rotation in radians. /// /// The amount of rotation, in radians. /// The . - public AffineTransformBuilder AppendRotateMatrixRadians(float radians) + public AffineTransformBuilder AppendRotationRadians(float radians) => this.AppendMatrix(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); + /// + /// Prepends a scale matrix from the given uniform scale. + /// + /// The uniform scale. + /// The . + public AffineTransformBuilder PrependScale(float scale) + => this.PrependMatrix(Matrix3x2.CreateScale(scale)); + + /// + /// Appends a scale matrix from the given uniform scale. + /// + /// The uniform scale. + /// The . + public AffineTransformBuilder AppendScale(float scale) + => this.AppendMatrix(Matrix3x2.CreateScale(scale)); + /// /// Prepends a scale matrix from the given vector scale. /// /// The horizontal and vertical scale. /// The . - public AffineTransformBuilder PrependScaleMatrix(SizeF scales) - => this.PrependMatrix(Matrix3x2Extensions.CreateScale(scales)); + public AffineTransformBuilder PrependScale(Vector2 scales) + => this.PrependMatrix(Matrix3x2.CreateScale(scales)); /// /// Appends a scale matrix from the given vector scale. /// /// The horizontal and vertical scale. /// The . - public AffineTransformBuilder AppendScaleMatrix(SizeF scales) - => this.AppendMatrix(Matrix3x2Extensions.CreateScale(scales)); + public AffineTransformBuilder AppendScale(Vector2 scales) + => this.AppendMatrix(Matrix3x2.CreateScale(scales)); + + /// + /// Prepends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public AffineTransformBuilder PrependScale(SizeF scale) + => this.PrependScale((Vector2)scale); + + /// + /// Appends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public AffineTransformBuilder AppendScale(SizeF scales) + => this.AppendScale((Vector2)scales); /// /// Prepends a centered skew matrix from the give angles in degrees. @@ -96,7 +128,7 @@ namespace SixLabors.ImageSharp.Processing /// The X angle, in degrees. /// The Y angle, in degrees. /// The . - public AffineTransformBuilder PrependSkewMatrixDegrees(float degreesX, float degreesY) + public AffineTransformBuilder PrependSkewDegrees(float degreesX, float degreesY) => this.PrependMatrix(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); /// @@ -105,7 +137,7 @@ namespace SixLabors.ImageSharp.Processing /// The X angle, in degrees. /// The Y angle, in degrees. /// The . - public AffineTransformBuilder AppendSkewMatrixDegrees(float degreesX, float degreesY) + public AffineTransformBuilder AppendSkewDegrees(float degreesX, float degreesY) => this.AppendMatrix(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); /// @@ -113,16 +145,32 @@ namespace SixLabors.ImageSharp.Processing /// /// The translation position. /// The . - public AffineTransformBuilder PrependTranslationMatrix(PointF position) - => this.PrependMatrix(Matrix3x2Extensions.CreateTranslation(position)); + public AffineTransformBuilder PrependTranslation(PointF position) + => this.PrependTranslation((Vector2)position); + + /// + /// Appends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public AffineTransformBuilder AppendTranslation(PointF position) + => this.AppendTranslation((Vector2)position); + + /// + /// Prepends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public AffineTransformBuilder PrependTranslation(Vector2 position) + => this.PrependMatrix(Matrix3x2.CreateTranslation(position)); /// /// Appends a translation matrix from the given vector. /// /// The translation position. /// The . - public AffineTransformBuilder AppendTranslationMatrix(PointF position) - => this.AppendMatrix(Matrix3x2Extensions.CreateTranslation(position)); + public AffineTransformBuilder AppendTranslation(Vector2 position) + => this.AppendMatrix(Matrix3x2.CreateTranslation(position)); /// /// Prepends a raw matrix. diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs index 564318e5e3..a29342ad46 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs @@ -74,9 +74,9 @@ namespace SixLabors.ImageSharp.Tests using (var blend = Image.Load(TestFile.Create(TestImages.Bmp.Car).Bytes)) { AffineTransformBuilder builder = new AffineTransformBuilder(blend.Size()) - .AppendRotateMatrixDegrees(45F) - .AppendScaleMatrix(new SizeF(.25F, .25F)) - .AppendTranslationMatrix(new PointF(10, 10)); + .AppendRotationDegrees(45F) + .AppendScale(new SizeF(.25F, .25F)) + .AppendTranslation(new PointF(10, 10)); // Apply a background color so we can see the translation. blend.Mutate(x => x.Transform(builder).BackgroundColor(NamedColors.HotPink)); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs index 1b4caee14f..639f4b46fa 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs @@ -36,13 +36,13 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms }); } - protected override void AppendTranslation(AffineTransformBuilder builder, PointF translate) => builder.AppendTranslationMatrix(translate); - protected override void AppendScale(AffineTransformBuilder builder, SizeF scale) => builder.AppendScaleMatrix(scale); - protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendRotateMatrixRadians(radians); + protected override void AppendTranslation(AffineTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); + protected override void AppendScale(AffineTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); + protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); - protected override void PrependTranslation(AffineTransformBuilder builder, PointF translate) => builder.PrependTranslationMatrix(translate); - protected override void PrependScale(AffineTransformBuilder builder, SizeF scale) => builder.PrependScaleMatrix(scale); - protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) => builder.PrependRotateMatrixRadians(radians); + protected override void PrependTranslation(AffineTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); + protected override void PrependScale(AffineTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); + protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians); protected override Vector2 Execute( AffineTransformBuilder builder, diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index 3d7fba2c19..e78bb2c6d9 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) - .AppendRotateMatrixDegrees(30); + .AppendRotationDegrees(30); image.Mutate(c => c.Transform(builder, resampler)); image.DebugSave(provider, resamplerName); @@ -102,9 +102,9 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { image.DebugSave(provider, $"_original"); AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) - .AppendRotateMatrixDegrees(angleDeg) - .AppendScaleMatrix(new SizeF(sx, sy)) - .AppendTranslationMatrix(new PointF(tx, ty)); + .AppendRotationDegrees(angleDeg) + .AppendScale(new SizeF(sx, sy)) + .AppendTranslation(new PointF(tx, ty)); this.PrintMatrix(builder.BuildMatrix()); @@ -124,8 +124,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) - .AppendRotateMatrixDegrees(angleDeg) - .AppendScaleMatrix(new SizeF(s, s)); + .AppendRotationDegrees(angleDeg) + .AppendScale(new SizeF(s, s)); image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic)); @@ -160,7 +160,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { image.DebugSave(provider, $"_original"); AffineTransformBuilder builder = new AffineTransformBuilder(rectangle) - .AppendScaleMatrix(new SizeF(2, 1.5F)); + .AppendScale(new SizeF(2, 1.5F)); image.Mutate(i => i.Transform(builder, KnownResamplers.Spline)); @@ -179,7 +179,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { AffineTransformBuilder builder = new AffineTransformBuilder(rectangle) - .AppendScaleMatrix(new SizeF(1F, 2F)); + .AppendScale(new SizeF(1F, 2F)); image.Mutate(i => i.Transform(builder, KnownResamplers.Spline)); @@ -197,8 +197,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) - .AppendRotateMatrixDegrees(50) - .AppendScaleMatrix(new SizeF(.6F, .6F)); + .AppendRotationDegrees(50) + .AppendScale(new SizeF(.6F, .6F)); image.Mutate(i => i.Transform(builder, sampler)); From 0774d5e794d41eb342b05af7ceb65df1c8258681 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 25 Nov 2018 23:18:17 +0100 Subject: [PATCH 346/381] Translation, Scale -> ProjectiveTransformBuilder --- .../Processing/AffineTransformBuilder.cs | 26 ++-- .../Processing/ProjectiveTransformBuilder.cs | 113 ++++++++++++++++-- .../ProjectiveTransformBuilderTests.cs | 54 +++------ 3 files changed, 131 insertions(+), 62 deletions(-) diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index 1620b72234..cd66272b42 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Processing public class AffineTransformBuilder { private readonly List matrices = new List(); - private readonly Rectangle rectangle; + private readonly Rectangle sourceRectangle; /// /// Initializes a new instance of the class. @@ -34,13 +34,13 @@ namespace SixLabors.ImageSharp.Processing Guard.MustBeGreaterThan(sourceRectangle.Width, 0, nameof(sourceRectangle)); Guard.MustBeGreaterThan(sourceRectangle.Height, 0, nameof(sourceRectangle)); - this.rectangle = sourceRectangle; + this.sourceRectangle = sourceRectangle; } /// /// Gets the source image size. /// - internal Size Size => this.rectangle.Size; + internal Size Size => this.sourceRectangle.Size; /// /// Prepends a centered rotation matrix using the given rotation in degrees. @@ -145,32 +145,32 @@ namespace SixLabors.ImageSharp.Processing /// /// The translation position. /// The . - public AffineTransformBuilder PrependTranslation(PointF position) - => this.PrependTranslation((Vector2)position); + public AffineTransformBuilder PrependTranslation(Vector2 position) + => this.PrependMatrix(Matrix3x2.CreateTranslation(position)); /// /// Appends a translation matrix from the given vector. /// /// The translation position. /// The . - public AffineTransformBuilder AppendTranslation(PointF position) - => this.AppendTranslation((Vector2)position); + public AffineTransformBuilder AppendTranslation(Vector2 position) + => this.AppendMatrix(Matrix3x2.CreateTranslation(position)); /// /// Prepends a translation matrix from the given vector. /// /// The translation position. /// The . - public AffineTransformBuilder PrependTranslation(Vector2 position) - => this.PrependMatrix(Matrix3x2.CreateTranslation(position)); + public AffineTransformBuilder PrependTranslation(PointF position) + => this.PrependTranslation((Vector2)position); /// /// Appends a translation matrix from the given vector. /// /// The translation position. /// The . - public AffineTransformBuilder AppendTranslation(Vector2 position) - => this.AppendMatrix(Matrix3x2.CreateTranslation(position)); + public AffineTransformBuilder AppendTranslation(PointF position) + => this.AppendTranslation((Vector2)position); /// /// Prepends a raw matrix. @@ -203,9 +203,9 @@ namespace SixLabors.ImageSharp.Processing Matrix3x2 matrix = Matrix3x2.Identity; // Translate the origin matrix to cater for source rectangle offsets. - if (!this.rectangle.Equals(default)) + if (!this.sourceRectangle.Equals(default)) { - matrix *= Matrix3x2.CreateTranslation(-this.rectangle.Location); + matrix *= Matrix3x2.CreateTranslation(-this.sourceRectangle.Location); } foreach (Matrix3x2 m in this.matrices) diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index be4c675189..6c5fb46259 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -14,18 +14,15 @@ namespace SixLabors.ImageSharp.Processing public class ProjectiveTransformBuilder { private readonly List matrices = new List(); - private Rectangle rectangle; + private Rectangle sourceRectangle; /// /// Initializes a new instance of the class. /// /// The source image size. public ProjectiveTransformBuilder(Size sourceSize) + : this(new Rectangle(Point.Empty, sourceSize)) { - Guard.MustBeGreaterThan(sourceSize.Width, 0, nameof(sourceSize)); - Guard.MustBeGreaterThan(sourceSize.Height, 0, nameof(sourceSize)); - - this.Size = sourceSize; } /// @@ -33,13 +30,18 @@ namespace SixLabors.ImageSharp.Processing /// /// The source rectangle. public ProjectiveTransformBuilder(Rectangle sourceRectangle) - : this(sourceRectangle.Size) - => this.rectangle = sourceRectangle; + { + Guard.MustBeGreaterThan(sourceRectangle.Width, 0, nameof(sourceRectangle)); + Guard.MustBeGreaterThan(sourceRectangle.Height, 0, nameof(sourceRectangle)); + + this.sourceRectangle = sourceRectangle; + } /// /// Gets the source image size. /// - internal Size Size { get; } + internal Size Size => this.sourceRectangle.Size; + /// /// Prepends a matrix that performs a tapering projective transform. @@ -61,6 +63,96 @@ namespace SixLabors.ImageSharp.Processing public ProjectiveTransformBuilder AppendTaperMatrix(TaperSide side, TaperCorner corner, float fraction) => this.AppendMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); + public void AppendRotationRadians(float radians) + { + throw new System.NotImplementedException(); + } + + public void PrependRotationRadians(float radians) + { + throw new System.NotImplementedException(); + } + + /// + /// Prepends a scale matrix from the given uniform scale. + /// + /// The uniform scale. + /// The . + public ProjectiveTransformBuilder PrependScale(float scale) + => this.PrependMatrix(Matrix4x4.CreateScale(scale)); + + /// + /// Appends a scale matrix from the given uniform scale. + /// + /// The uniform scale. + /// The . + public ProjectiveTransformBuilder AppendScale(float scale) + => this.AppendMatrix(Matrix4x4.CreateScale(scale)); + + /// + /// Prepends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public ProjectiveTransformBuilder PrependScale(Vector2 scales) + => this.PrependMatrix(Matrix4x4.CreateScale(new Vector3(scales, 1f))); + + /// + /// Appends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public ProjectiveTransformBuilder AppendScale(Vector2 scales) + => this.AppendMatrix(Matrix4x4.CreateScale(new Vector3(scales, 1f))); + + /// + /// Prepends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public ProjectiveTransformBuilder PrependScale(SizeF scale) + => this.PrependScale((Vector2)scale); + + /// + /// Appends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public ProjectiveTransformBuilder AppendScale(SizeF scales) + => this.AppendScale((Vector2)scales); + + /// + /// Prepends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public ProjectiveTransformBuilder PrependTranslation(Vector2 position) + => this.PrependMatrix(Matrix4x4.CreateTranslation(new Vector3(position, 0))); + + /// + /// Appends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public ProjectiveTransformBuilder AppendTranslation(Vector2 position) + => this.AppendMatrix(Matrix4x4.CreateTranslation(new Vector3(position, 0))); + + /// + /// Prepends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public ProjectiveTransformBuilder PrependTranslation(PointF position) + => this.PrependTranslation((Vector2)position); + + /// + /// Appends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public ProjectiveTransformBuilder AppendTranslation(PointF position) + => this.AppendTranslation((Vector2)position); + /// /// Prepends a raw matrix. /// @@ -92,9 +184,9 @@ namespace SixLabors.ImageSharp.Processing Matrix4x4 matrix = Matrix4x4.Identity; // Translate the origin matrix to cater for source rectangle offsets. - if (!this.rectangle.Equals(default)) + if (!this.sourceRectangle.Equals(default)) { - matrix *= Matrix4x4.CreateTranslation(new Vector3(-this.rectangle.Location, 0)); + matrix *= Matrix4x4.CreateTranslation(new Vector3(-this.sourceRectangle.Location, 0)); } foreach (Matrix4x4 m in this.matrices) @@ -109,5 +201,6 @@ namespace SixLabors.ImageSharp.Processing /// Removes all matrices from the builder. /// public void Clear() => this.matrices.Clear(); + } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs index 3dfc42d4f7..0d9bd301dc 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs @@ -9,7 +9,7 @@ using Xunit; namespace SixLabors.ImageSharp.Tests.Processing.Transforms { - public class ProjectiveTransformBuilderTests + public class ProjectiveTransformBuilderTests : TransformBuilderTestBase { [Fact] public void ConstructorAssignsProperties() @@ -34,45 +34,21 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms var builder = new ProjectiveTransformBuilder(new Rectangle(Point.Empty, s)); }); } - - [Fact] - public void AppendPrependOpposite() - { - var rectangle = new Rectangle(-1, -1, 3, 3); - var b1 = new ProjectiveTransformBuilder(rectangle); - var b2 = new ProjectiveTransformBuilder(rectangle); - - const float pi = (float)Math.PI; - - Matrix4x4 m4 = Matrix4x4.Identity; - m4.M31 = pi; - - // Forwards - b1.AppendMatrix(m4) - .AppendTaperMatrix(TaperSide.Left, TaperCorner.LeftOrTop, pi); - - // Backwards - b2.PrependTaperMatrix(TaperSide.Left, TaperCorner.LeftOrTop, pi) - .PrependMatrix(m4); - - Assert.Equal(b1.BuildMatrix(), b2.BuildMatrix()); - } - - [Fact] - public void BuilderCanClear() + protected override void AppendTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); + protected override void AppendScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); + protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); + + protected override void PrependTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); + protected override void PrependScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); + protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians); + + protected override Vector2 Execute( + ProjectiveTransformBuilder builder, + Rectangle rectangle, + Vector2 sourcePoint) { - var rectangle = new Rectangle(0, 0, 3, 3); - var builder = new ProjectiveTransformBuilder(rectangle); - Matrix4x4 matrix = Matrix4x4.Identity; - matrix.M31 = (float)Math.PI; - - Assert.Equal(Matrix4x4.Identity, builder.BuildMatrix()); - - builder.AppendMatrix(matrix); - Assert.NotEqual(Matrix4x4.Identity, builder.BuildMatrix()); - - builder.Clear(); - Assert.Equal(Matrix4x4.Identity, builder.BuildMatrix()); + Matrix4x4 matrix = builder.BuildMatrix(); + return Vector2.Transform(sourcePoint, matrix); } } } From e5f7b12c7ee165b2996cfe3d704c9ce6ac2e6e2d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 25 Nov 2018 23:29:34 +0100 Subject: [PATCH 347/381] extend ProjectiveTransformBuilder --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 2 +- .../Processing/AffineTransformBuilder.cs | 29 +++++++------- .../Processing/ProjectiveTransformBuilder.cs | 38 ++++++++++++++++--- .../ImageSharp.Tests/Drawing/DrawImageTest.cs | 2 +- .../Transforms/AffineTransformBuilderTests.cs | 4 +- .../Transforms/AffineTransformTests.cs | 8 ++-- .../ProjectiveTransformBuilderTests.cs | 5 ++- .../Transforms/TransformBuilderTestBase.cs | 2 +- 8 files changed, 60 insertions(+), 30 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 45556741e6..c0c8e07e6f 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp /// Converts degrees to radians /// [MethodImpl(InliningOptions.ShortMethod)] - public static float ToRadian(float degrees) + public static float DegreesToRadians(float degrees) { return degrees * ((float)Math.PI / 180f); } diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index cd66272b42..1f26d079d4 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -42,37 +42,38 @@ namespace SixLabors.ImageSharp.Processing /// internal Size Size => this.sourceRectangle.Size; + /// - /// Prepends a centered rotation matrix using the given rotation in degrees. + /// Prepends a centered rotation matrix using the given rotation in radians. /// - /// The amount of rotation, in degrees. + /// The amount of rotation, in radians. /// The . - public AffineTransformBuilder PrependRotationDegrees(float degrees) - => this.PrependMatrix(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); + public AffineTransformBuilder PrependCenteredRotationRadians(float radians) + => this.PrependMatrix(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); /// - /// Prepends a centered rotation matrix using the given rotation in radians. + /// Appends a centered rotation matrix using the given rotation in radians. /// /// The amount of rotation, in radians. /// The . - public AffineTransformBuilder PrependRotationRadians(float radians) - => this.PrependMatrix(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); + public AffineTransformBuilder AppendCenteredRotationRadians(float radians) + => this.AppendMatrix(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); /// - /// Appends a centered rotation matrix using the given rotation in degrees. + /// Prepends a centered rotation matrix using the given rotation in degrees. /// /// The amount of rotation, in degrees. /// The . - public AffineTransformBuilder AppendRotationDegrees(float degrees) - => this.AppendRotationRadians(ImageMaths.ToRadian(degrees)); + public AffineTransformBuilder PrependCenteredRotationDegrees(float degrees) + => this.PrependCenteredRotationRadians(ImageMaths.DegreesToRadians(degrees)); /// - /// Appends a centered rotation matrix using the given rotation in radians. + /// Appends a centered rotation matrix using the given rotation in degrees. /// - /// The amount of rotation, in radians. + /// The amount of rotation, in degrees. /// The . - public AffineTransformBuilder AppendRotationRadians(float radians) - => this.AppendMatrix(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); + public AffineTransformBuilder AppendCenteredRotationDegrees(float degrees) + => this.AppendCenteredRotationRadians(ImageMaths.DegreesToRadians(degrees)); /// /// Prepends a scale matrix from the given uniform scale. diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index 6c5fb46259..58c02108ac 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Processing Guard.MustBeGreaterThan(sourceRectangle.Height, 0, nameof(sourceRectangle)); this.sourceRectangle = sourceRectangle; - } + } /// /// Gets the source image size. @@ -63,16 +63,44 @@ namespace SixLabors.ImageSharp.Processing public ProjectiveTransformBuilder AppendTaperMatrix(TaperSide side, TaperCorner corner, float fraction) => this.AppendMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); - public void AppendRotationRadians(float radians) + /// + /// Prepends a centered rotation matrix using the given rotation in radians. + /// + /// The amount of rotation, in radians. + /// The . + public ProjectiveTransformBuilder PrependCenteredRotationRadians(float radians) { - throw new System.NotImplementedException(); + var m = new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); + return this.PrependMatrix(m); } - public void PrependRotationRadians(float radians) + /// + /// Appends a centered rotation matrix using the given rotation in radians. + /// + /// The amount of rotation, in radians. + /// The . + public ProjectiveTransformBuilder AppendCenteredRotationRadians(float radians) { - throw new System.NotImplementedException(); + var m = new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); + return this.AppendMatrix(m); } + /// + /// Prepends a centered rotation matrix using the given rotation in degrees. + /// + /// The amount of rotation, in degrees. + /// The . + public ProjectiveTransformBuilder PrependCenteredRotationDegrees(float degrees) + => this.PrependCenteredRotationRadians(ImageMaths.DegreesToRadians(degrees)); + + /// + /// Appends a centered rotation matrix using the given rotation in degrees. + /// + /// The amount of rotation, in degrees. + /// The . + public ProjectiveTransformBuilder AppendCenteredRotationDegrees(float degrees) + => this.AppendCenteredRotationRadians(ImageMaths.DegreesToRadians(degrees)); + /// /// Prepends a scale matrix from the given uniform scale. /// diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs index a29342ad46..2f89236544 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Tests using (var blend = Image.Load(TestFile.Create(TestImages.Bmp.Car).Bytes)) { AffineTransformBuilder builder = new AffineTransformBuilder(blend.Size()) - .AppendRotationDegrees(45F) + .AppendCenteredRotationDegrees(45F) .AppendScale(new SizeF(.25F, .25F)) .AppendTranslation(new PointF(10, 10)); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs index 639f4b46fa..2a43e56e70 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs @@ -38,11 +38,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected override void AppendTranslation(AffineTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); protected override void AppendScale(AffineTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); - protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); + protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendCenteredRotationRadians(radians); protected override void PrependTranslation(AffineTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); protected override void PrependScale(AffineTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); - protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians); + protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) => builder.PrependCenteredRotationRadians(radians); protected override Vector2 Execute( AffineTransformBuilder builder, diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index e78bb2c6d9..f86db5641f 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) - .AppendRotationDegrees(30); + .AppendCenteredRotationDegrees(30); image.Mutate(c => c.Transform(builder, resampler)); image.DebugSave(provider, resamplerName); @@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { image.DebugSave(provider, $"_original"); AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) - .AppendRotationDegrees(angleDeg) + .AppendCenteredRotationDegrees(angleDeg) .AppendScale(new SizeF(sx, sy)) .AppendTranslation(new PointF(tx, ty)); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) - .AppendRotationDegrees(angleDeg) + .AppendCenteredRotationDegrees(angleDeg) .AppendScale(new SizeF(s, s)); image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic)); @@ -197,7 +197,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) - .AppendRotationDegrees(50) + .AppendCenteredRotationDegrees(50) .AppendScale(new SizeF(.6F, .6F)); image.Mutate(i => i.Transform(builder, sampler)); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs index 0d9bd301dc..f467bed40c 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs @@ -34,13 +34,14 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms var builder = new ProjectiveTransformBuilder(new Rectangle(Point.Empty, s)); }); } + protected override void AppendTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); protected override void AppendScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); - protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); + protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendCenteredRotationRadians(radians); protected override void PrependTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); protected override void PrependScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); - protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians); + protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.PrependCenteredRotationRadians(radians); protected override Vector2 Execute( ProjectiveTransformBuilder builder, diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs index d109387cc4..3f259c9aa2 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs @@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected abstract void PrependRotationRadians(TBuilder builder, float radians); protected virtual void AppendRotationDegrees(TBuilder builder, float degrees) => - this.AppendRotationRadians(builder, ImageMaths.ToRadian(degrees)); + this.AppendRotationRadians(builder, ImageMaths.DegreesToRadians(degrees)); protected abstract Vector2 Execute(TBuilder builder, Rectangle rectangle, Vector2 sourcePoint); From 59f47d457b1c72d8ae2baa49fdf351932f7bb9fd Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 25 Nov 2018 23:31:05 +0100 Subject: [PATCH 348/381] fix trailing whitespace warnings --- src/ImageSharp/Processing/AffineTransformBuilder.cs | 1 - src/ImageSharp/Processing/ProjectiveTransformBuilder.cs | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index 1f26d079d4..a1305d1212 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -42,7 +42,6 @@ namespace SixLabors.ImageSharp.Processing /// internal Size Size => this.sourceRectangle.Size; - /// /// Prepends a centered rotation matrix using the given rotation in radians. /// diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index 58c02108ac..9bcbaf8343 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -42,7 +42,6 @@ namespace SixLabors.ImageSharp.Processing /// internal Size Size => this.sourceRectangle.Size; - /// /// Prepends a matrix that performs a tapering projective transform. /// @@ -229,6 +228,5 @@ namespace SixLabors.ImageSharp.Processing /// Removes all matrices from the builder. /// public void Clear() => this.matrices.Clear(); - } } \ No newline at end of file From 103d12901234874c91131faeedc1123088830581 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 26 Nov 2018 01:09:47 +0100 Subject: [PATCH 349/381] Make AffineTransformProcessor and AffineTransformBuilder API more flexible --- .../Processing/AffineTransformBuilder.cs | 83 ++++++++----------- .../Transforms/AffineTransformProcessor.cs | 6 +- .../Processing/TransformExtensions.cs | 71 ++++++++++++++-- .../ImageSharp.Tests/Drawing/DrawImageTest.cs | 2 +- .../Transforms/AffineTransformBuilderTests.cs | 28 +------ .../Transforms/AffineTransformTests.cs | 18 ++-- .../ProjectiveTransformBuilderTests.cs | 2 + .../Transforms/TransformBuilderTestBase.cs | 18 +++- 8 files changed, 136 insertions(+), 92 deletions(-) diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index a1305d1212..42d555f203 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.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 System.Numerics; using SixLabors.ImageSharp.Processing.Processors.Transforms; @@ -13,34 +14,7 @@ namespace SixLabors.ImageSharp.Processing /// public class AffineTransformBuilder { - private readonly List matrices = new List(); - private readonly Rectangle sourceRectangle; - - /// - /// Initializes a new instance of the class. - /// - /// The source image size. - public AffineTransformBuilder(Size sourceSize) - : this(new Rectangle(Point.Empty, sourceSize)) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The source rectangle. - public AffineTransformBuilder(Rectangle sourceRectangle) - { - Guard.MustBeGreaterThan(sourceRectangle.Width, 0, nameof(sourceRectangle)); - Guard.MustBeGreaterThan(sourceRectangle.Height, 0, nameof(sourceRectangle)); - - this.sourceRectangle = sourceRectangle; - } - - /// - /// Gets the source image size. - /// - internal Size Size => this.sourceRectangle.Size; + private readonly List> matrixFactories = new List>(); /// /// Prepends a centered rotation matrix using the given rotation in radians. @@ -48,7 +22,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in radians. /// The . public AffineTransformBuilder PrependCenteredRotationRadians(float radians) - => this.PrependMatrix(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); + => this.Prepend(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); /// /// Appends a centered rotation matrix using the given rotation in radians. @@ -56,7 +30,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in radians. /// The . public AffineTransformBuilder AppendCenteredRotationRadians(float radians) - => this.AppendMatrix(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); + => this.Append(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); /// /// Prepends a centered rotation matrix using the given rotation in degrees. @@ -129,7 +103,7 @@ namespace SixLabors.ImageSharp.Processing /// The Y angle, in degrees. /// The . public AffineTransformBuilder PrependSkewDegrees(float degreesX, float degreesY) - => this.PrependMatrix(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); + => this.Prepend(size => TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, size)); /// /// Appends a centered skew matrix from the give angles in degrees. @@ -138,7 +112,7 @@ namespace SixLabors.ImageSharp.Processing /// The Y angle, in degrees. /// The . public AffineTransformBuilder AppendSkewDegrees(float degreesX, float degreesY) - => this.AppendMatrix(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); + => this.Append(size => TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, size)); /// /// Prepends a translation matrix from the given vector. @@ -179,7 +153,7 @@ namespace SixLabors.ImageSharp.Processing /// The . public AffineTransformBuilder PrependMatrix(Matrix3x2 matrix) { - this.matrices.Insert(0, matrix); + this.matrixFactories.Insert(0, _ => matrix); return this; } @@ -190,35 +164,50 @@ namespace SixLabors.ImageSharp.Processing /// The . public AffineTransformBuilder AppendMatrix(Matrix3x2 matrix) { - this.matrices.Add(matrix); + this.matrixFactories.Add(_ => matrix); return this; } /// - /// Returns the combined matrix. + /// Returns the combined matrix for a given source size. + /// + /// The source image size + /// The . + public Matrix3x2 BuildMatrix(Size sourceSize) => this.BuildMatrix(new Rectangle(Point.Empty, sourceSize)); + + /// + /// Returns the combined matrix for a given source rectangle. /// + /// The rectangle in the source image /// The . - public Matrix3x2 BuildMatrix() + public Matrix3x2 BuildMatrix(Rectangle sourceRectangle) { - Matrix3x2 matrix = Matrix3x2.Identity; + Guard.MustBeGreaterThan(sourceRectangle.Width, 0, nameof(sourceRectangle)); + Guard.MustBeGreaterThan(sourceRectangle.Height, 0, nameof(sourceRectangle)); // Translate the origin matrix to cater for source rectangle offsets. - if (!this.sourceRectangle.Equals(default)) - { - matrix *= Matrix3x2.CreateTranslation(-this.sourceRectangle.Location); - } + var matrix = Matrix3x2.CreateTranslation(-sourceRectangle.Location); - foreach (Matrix3x2 m in this.matrices) + Size size = sourceRectangle.Size; + + foreach (Func factory in this.matrixFactories) { - matrix *= m; + matrix *= factory(size); } return matrix; } - /// - /// Removes all matrices from the builder. - /// - public void Clear() => this.matrices.Clear(); + private AffineTransformBuilder Prepend(Func factory) + { + this.matrixFactories.Insert(0, factory); + return this; + } + + private AffineTransformBuilder Append(Func factory) + { + this.matrixFactories.Add(factory); + return this; + } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index 2370adb862..f357b6c277 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -24,13 +24,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// The transform matrix. /// The sampler to perform the transform operation. - /// The source image size. - public AffineTransformProcessor(Matrix3x2 matrix, IResampler sampler, Size sourceSize) + /// The target dimensions. + public AffineTransformProcessor(Matrix3x2 matrix, IResampler sampler, Size targetDimensions) { Guard.NotNull(sampler, nameof(sampler)); this.Sampler = sampler; this.TransformMatrix = matrix; - this.TargetDimensions = TransformUtils.GetTransformedSize(sourceSize, matrix); + this.TargetDimensions = targetDimensions;; } /// diff --git a/src/ImageSharp/Processing/TransformExtensions.cs b/src/ImageSharp/Processing/TransformExtensions.cs index ea789eb3d7..de4a3e5ba7 100644 --- a/src/ImageSharp/Processing/TransformExtensions.cs +++ b/src/ImageSharp/Processing/TransformExtensions.cs @@ -1,8 +1,11 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System.Numerics; + using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Transforms; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing { @@ -11,6 +14,29 @@ namespace SixLabors.ImageSharp.Processing /// public static class TransformExtensions { + /// + /// Performs an affine transform of an image using the specified sampling algorithm. + /// + /// The pixel format. + /// The . + /// The source rectangle + /// The transformation matrix. + /// The size of the result image. + /// The to perform the resampling. + /// The + public static IImageProcessingContext Transform( + this IImageProcessingContext ctx, + Rectangle sourceRectangle, + Matrix3x2 transform, + Size targetDimensions, + IResampler sampler) + where TPixel : struct, IPixel + { + return ctx.ApplyProcessor( + new AffineTransformProcessor(transform, sampler, targetDimensions), + sourceRectangle); + } + /// /// Performs an affine transform of an image. /// @@ -18,7 +44,9 @@ namespace SixLabors.ImageSharp.Processing /// The image to transform. /// The affine transform builder. /// The - public static IImageProcessingContext Transform(this IImageProcessingContext source, AffineTransformBuilder builder) + public static IImageProcessingContext Transform( + this IImageProcessingContext source, + AffineTransformBuilder builder) where TPixel : struct, IPixel => Transform(source, builder, KnownResamplers.Bicubic); @@ -26,13 +54,39 @@ namespace SixLabors.ImageSharp.Processing /// Performs an affine transform of an image using the specified sampling algorithm. /// /// The pixel format. - /// The image to transform. + /// The . + /// The source rectangle + /// The affine transform builder. + /// The to perform the resampling. + /// The + public static IImageProcessingContext Transform( + this IImageProcessingContext ctx, + Rectangle sourceRectangle, + AffineTransformBuilder builder, + IResampler sampler) + where TPixel : struct, IPixel + { + Matrix3x2 transform = builder.BuildMatrix(sourceRectangle); + Size targetDimensions = TransformUtils.GetTransformedSize(sourceRectangle.Size, transform); + return ctx.Transform(sourceRectangle, transform, targetDimensions, sampler); + } + + /// + /// Performs an affine transform of an image using the specified sampling algorithm. + /// + /// The pixel format. + /// The . /// The affine transform builder. /// The to perform the resampling. /// The - public static IImageProcessingContext Transform(this IImageProcessingContext source, AffineTransformBuilder builder, IResampler sampler) + public static IImageProcessingContext Transform( + this IImageProcessingContext ctx, + AffineTransformBuilder builder, + IResampler sampler) where TPixel : struct, IPixel - => source.ApplyProcessor(new AffineTransformProcessor(builder.BuildMatrix(), sampler, builder.Size)); + { + return ctx.Transform(new Rectangle(Point.Empty, ctx.GetCurrentSize()), builder, sampler); + } /// /// Performs a projective transform of an image. @@ -41,7 +95,9 @@ namespace SixLabors.ImageSharp.Processing /// The image to transform. /// The affine transform builder. /// The - public static IImageProcessingContext Transform(this IImageProcessingContext source, ProjectiveTransformBuilder builder) + public static IImageProcessingContext Transform( + this IImageProcessingContext source, + ProjectiveTransformBuilder builder) where TPixel : struct, IPixel => Transform(source, builder, KnownResamplers.Bicubic); @@ -53,7 +109,10 @@ namespace SixLabors.ImageSharp.Processing /// The projective transform builder. /// The to perform the resampling. /// The - public static IImageProcessingContext Transform(this IImageProcessingContext source, ProjectiveTransformBuilder builder, IResampler sampler) + public static IImageProcessingContext Transform( + this IImageProcessingContext source, + ProjectiveTransformBuilder builder, + IResampler sampler) where TPixel : struct, IPixel => source.ApplyProcessor(new ProjectiveTransformProcessor(builder.BuildMatrix(), sampler, builder.Size)); } diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs index 2f89236544..f3772e3aa3 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Tests using (Image image = provider.GetImage()) using (var blend = Image.Load(TestFile.Create(TestImages.Bmp.Car).Bytes)) { - AffineTransformBuilder builder = new AffineTransformBuilder(blend.Size()) + AffineTransformBuilder builder = new AffineTransformBuilder() .AppendCenteredRotationDegrees(45F) .AppendScale(new SizeF(.25F, .25F)) .AppendTranslation(new PointF(10, 10)); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs index 2a43e56e70..cbbf59caf5 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs @@ -12,30 +12,6 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { public class AffineTransformBuilderTests : TransformBuilderTestBase { - [Fact] - public void ConstructorAssignsProperties() - { - var s = new Size(1, 1); - var builder = new AffineTransformBuilder(new Rectangle(Point.Empty, s)); - Assert.Equal(s, builder.Size); - } - - [Fact] - public void ConstructorThrowsInvalid() - { - Assert.Throws(() => - { - var s = new Size(0, 1); - var builder = new AffineTransformBuilder(new Rectangle(Point.Empty, s)); - }); - - Assert.Throws(() => - { - var s = new Size(1, 0); - var builder = new AffineTransformBuilder(new Rectangle(Point.Empty, s)); - }); - } - protected override void AppendTranslation(AffineTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); protected override void AppendScale(AffineTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendCenteredRotationRadians(radians); @@ -44,12 +20,14 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected override void PrependScale(AffineTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) => builder.PrependCenteredRotationRadians(radians); + protected override AffineTransformBuilder CreateBuilder(Rectangle rectangle) => new AffineTransformBuilder(); + protected override Vector2 Execute( AffineTransformBuilder builder, Rectangle rectangle, Vector2 sourcePoint) { - Matrix3x2 matrix = builder.BuildMatrix(); + Matrix3x2 matrix = builder.BuildMatrix(rectangle); return Vector2.Transform(sourcePoint, matrix); } } diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index f86db5641f..0c167d7f97 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms IResampler resampler = GetResampler(resamplerName); using (Image image = provider.GetImage()) { - AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) + AffineTransformBuilder builder = new AffineTransformBuilder() .AppendCenteredRotationDegrees(30); image.Mutate(c => c.Transform(builder, resampler)); @@ -101,12 +101,12 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { image.DebugSave(provider, $"_original"); - AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) + AffineTransformBuilder builder = new AffineTransformBuilder() .AppendCenteredRotationDegrees(angleDeg) .AppendScale(new SizeF(sx, sy)) .AppendTranslation(new PointF(tx, ty)); - this.PrintMatrix(builder.BuildMatrix()); + this.PrintMatrix(builder.BuildMatrix(image.Size())); image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic)); @@ -123,7 +123,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { using (Image image = provider.GetImage()) { - AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) + AffineTransformBuilder builder = new AffineTransformBuilder() .AppendCenteredRotationDegrees(angleDeg) .AppendScale(new SizeF(s, s)); @@ -159,10 +159,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { image.DebugSave(provider, $"_original"); - AffineTransformBuilder builder = new AffineTransformBuilder(rectangle) + AffineTransformBuilder builder = new AffineTransformBuilder() .AppendScale(new SizeF(2, 1.5F)); - image.Mutate(i => i.Transform(builder, KnownResamplers.Spline)); + image.Mutate(i => i.Transform(rectangle, builder, KnownResamplers.Spline)); image.DebugSave(provider); image.CompareToReferenceOutput(ValidatorComparer, provider); @@ -178,10 +178,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { - AffineTransformBuilder builder = new AffineTransformBuilder(rectangle) + AffineTransformBuilder builder = new AffineTransformBuilder() .AppendScale(new SizeF(1F, 2F)); - image.Mutate(i => i.Transform(builder, KnownResamplers.Spline)); + image.Mutate(i => i.Transform(rectangle, builder, KnownResamplers.Spline)); image.DebugSave(provider); image.CompareToReferenceOutput(ValidatorComparer, provider); @@ -196,7 +196,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms IResampler sampler = GetResampler(resamplerName); using (Image image = provider.GetImage()) { - AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) + AffineTransformBuilder builder = new AffineTransformBuilder() .AppendCenteredRotationDegrees(50) .AppendScale(new SizeF(.6F, .6F)); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs index f467bed40c..14ed57033e 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs @@ -35,6 +35,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms }); } + protected override ProjectiveTransformBuilder CreateBuilder(Rectangle rectangle) => new ProjectiveTransformBuilder(rectangle); + protected override void AppendTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); protected override void AppendScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendCenteredRotationRadians(radians); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs index 3f259c9aa2..648ed5861f 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs @@ -129,9 +129,25 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms Assert.Equal(p1, p2, Comparer); } + [Theory] + [InlineData(0, 1)] + [InlineData(1, 0)] + [InlineData(-1, 0)] + public void ThrowsForInvalidSizes(int width, int height) + { + var size = new Size(width, height); + + Assert.ThrowsAny( + () => + { + TBuilder builder = this.CreateBuilder(size); + this.Execute(builder, new Rectangle(Point.Empty, size), Vector2.Zero); + }); + } + protected TBuilder CreateBuilder(Size size) => this.CreateBuilder(new Rectangle(Point.Empty, size)); - protected virtual TBuilder CreateBuilder(Rectangle rectangle) => (TBuilder)Activator.CreateInstance(typeof(TBuilder), rectangle); + protected abstract TBuilder CreateBuilder(Rectangle rectangle); protected abstract void AppendTranslation(TBuilder builder, PointF translate); protected abstract void AppendScale(TBuilder builder, SizeF scale); From eab8a5677c73074f68cb369814a27beaf2e57641 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 26 Nov 2018 01:19:53 +0100 Subject: [PATCH 350/381] fix rotate and skew processors --- .../Processors/Transforms/RotateProcessor.cs | 10 +++++++++- .../Processing/Processors/Transforms/SkewProcessor.cs | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs index 57cca4bf9e..69ecf59215 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs @@ -2,6 +2,8 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Numerics; + using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.ParallelUtils; @@ -34,12 +36,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The sampler to perform the rotating operation. /// The source image size public RotateProcessor(float degrees, IResampler sampler, Size sourceSize) - : base( + : this( TransformUtils.CreateRotationMatrixDegrees(degrees, sourceSize), sampler, sourceSize) => this.Degrees = degrees; + // Helper constructor + private RotateProcessor(Matrix3x2 rotationMatrix, IResampler sampler, Size sourceSize) + : base(rotationMatrix, sampler, TransformUtils.GetTransformedSize(sourceSize, rotationMatrix)) + { + } + /// /// Gets the angle of rotation in degrees. /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs index 4a006a9dfe..c7b1d74104 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System.Numerics; + using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; @@ -32,7 +34,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The sampler to perform the skew operation. /// The source image size public SkewProcessor(float degreesX, float degreesY, IResampler sampler, Size sourceSize) - : base( + : this( TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, sourceSize), sampler, sourceSize) @@ -41,6 +43,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.DegreesY = degreesY; } + // Helper constructor: + private SkewProcessor(Matrix3x2 skewMatrix, IResampler sampler, Size sourceSize) + : base(skewMatrix, sampler, TransformUtils.GetTransformedSize(sourceSize, skewMatrix)) + { + } + /// /// Gets the angle of rotation along the x-axis in degrees. /// From 81e16e48a3141ecd1e5fdfd62ab07cc6449600bb Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 26 Nov 2018 01:29:31 +0100 Subject: [PATCH 351/381] StyleCop --- .../Processors/Transforms/AffineTransformProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index f357b6c277..aabaa63cf9 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Guard.NotNull(sampler, nameof(sampler)); this.Sampler = sampler; this.TransformMatrix = matrix; - this.TargetDimensions = targetDimensions;; + this.TargetDimensions = targetDimensions; } /// From bbfb2a0ef9249183bce9f8128d4ad058361a8ef2 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 26 Nov 2018 02:37:10 +0100 Subject: [PATCH 352/381] Rotation around custom center point. Rename PrependCenteredRotationRadians back to PrependRotationRadians --- .../Processing/AffineTransformBuilder.cs | 40 ++++++++++++---- .../Processing/ProjectiveTransformBuilder.cs | 35 ++++++++++++-- .../ImageSharp.Tests/Drawing/DrawImageTest.cs | 2 +- .../Transforms/AffineTransformBuilderTests.cs | 8 +++- .../Transforms/AffineTransformTests.cs | 8 ++-- .../ProjectiveTransformBuilderTests.cs | 8 +++- .../Transforms/TransformBuilderTestBase.cs | 46 +++++++++++++++++-- 7 files changed, 121 insertions(+), 26 deletions(-) diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index 42d555f203..eab75cfdbe 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -20,33 +20,55 @@ namespace SixLabors.ImageSharp.Processing /// Prepends a centered rotation matrix using the given rotation in radians. /// /// The amount of rotation, in radians. + /// The rotation center point /// The . - public AffineTransformBuilder PrependCenteredRotationRadians(float radians) - => this.Prepend(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); + public AffineTransformBuilder PrependRotationRadians(float radians, Vector2 centerPoint) + => this.PrependMatrix(Matrix3x2.CreateRotation(radians, centerPoint)); /// /// Appends a centered rotation matrix using the given rotation in radians. /// /// The amount of rotation, in radians. + /// The rotation center point + /// The . + public AffineTransformBuilder AppendRotationRadians(float radians, Vector2 centerPoint) + => this.AppendMatrix(Matrix3x2.CreateRotation(radians, centerPoint)); + + /// + /// Prepends a rotation matrix using the given rotation angle in radians + /// and the image center point as rotation center. + /// + /// The amount of rotation, in radians. + /// The . + public AffineTransformBuilder PrependRotationRadians(float radians) + => this.Prepend(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); + + /// + /// Appends a rotation matrix using the given rotation angle in radians + /// and the image center point as rotation center. + /// + /// The amount of rotation, in radians. /// The . - public AffineTransformBuilder AppendCenteredRotationRadians(float radians) + public AffineTransformBuilder AppendRotationRadians(float radians) => this.Append(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); /// - /// Prepends a centered rotation matrix using the given rotation in degrees. + /// Prepends a rotation matrix using the given rotation angle in degrees + /// and the image center point as rotation center. /// /// The amount of rotation, in degrees. /// The . - public AffineTransformBuilder PrependCenteredRotationDegrees(float degrees) - => this.PrependCenteredRotationRadians(ImageMaths.DegreesToRadians(degrees)); + public AffineTransformBuilder PrependRotationDegrees(float degrees) + => this.PrependRotationRadians(ImageMaths.DegreesToRadians(degrees)); /// - /// Appends a centered rotation matrix using the given rotation in degrees. + /// Appends a rotation matrix using the given rotation angle in degrees + /// and the image center point as rotation center. /// /// The amount of rotation, in degrees. /// The . - public AffineTransformBuilder AppendCenteredRotationDegrees(float degrees) - => this.AppendCenteredRotationRadians(ImageMaths.DegreesToRadians(degrees)); + public AffineTransformBuilder AppendRotationDegrees(float degrees) + => this.AppendRotationRadians(ImageMaths.DegreesToRadians(degrees)); /// /// Prepends a scale matrix from the given uniform scale. diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index 9bcbaf8343..8bde90d51a 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.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 System.Numerics; using SixLabors.ImageSharp.Processing.Processors.Transforms; @@ -67,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing /// /// The amount of rotation, in radians. /// The . - public ProjectiveTransformBuilder PrependCenteredRotationRadians(float radians) + public ProjectiveTransformBuilder PrependRotationRadians(float radians) { var m = new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); return this.PrependMatrix(m); @@ -78,27 +79,51 @@ namespace SixLabors.ImageSharp.Processing /// /// The amount of rotation, in radians. /// The . - public ProjectiveTransformBuilder AppendCenteredRotationRadians(float radians) + public ProjectiveTransformBuilder AppendRotationRadians(float radians) { var m = new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); return this.AppendMatrix(m); } + /// + /// Appends a centered rotation matrix using the given rotation in radians. + /// + /// The amount of rotation, in radians. + /// The rotation center. + /// The . + internal ProjectiveTransformBuilder PrependRotationRadians(float radians, Vector2 centerPoint) + { + var m = Matrix4x4.CreateRotationZ(radians, new Vector3(centerPoint, 0)); + return this.PrependMatrix(m); + } + + /// + /// Appends a centered rotation matrix using the given rotation in radians. + /// + /// The amount of rotation, in radians. + /// The rotation center. + /// The . + internal ProjectiveTransformBuilder AppendRotationRadians(float radians, Vector2 centerPoint) + { + var m = Matrix4x4.CreateRotationZ(radians, new Vector3(centerPoint, 0)); + return this.AppendMatrix(m); + } + /// /// Prepends a centered rotation matrix using the given rotation in degrees. /// /// The amount of rotation, in degrees. /// The . public ProjectiveTransformBuilder PrependCenteredRotationDegrees(float degrees) - => this.PrependCenteredRotationRadians(ImageMaths.DegreesToRadians(degrees)); + => this.PrependRotationRadians(ImageMaths.DegreesToRadians(degrees)); /// /// Appends a centered rotation matrix using the given rotation in degrees. /// /// The amount of rotation, in degrees. /// The . - public ProjectiveTransformBuilder AppendCenteredRotationDegrees(float degrees) - => this.AppendCenteredRotationRadians(ImageMaths.DegreesToRadians(degrees)); + public ProjectiveTransformBuilder AppendRotationDegrees(float degrees) + => this.AppendRotationRadians(ImageMaths.DegreesToRadians(degrees)); /// /// Prepends a scale matrix from the given uniform scale. diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs index f3772e3aa3..374454afba 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Tests using (var blend = Image.Load(TestFile.Create(TestImages.Bmp.Car).Bytes)) { AffineTransformBuilder builder = new AffineTransformBuilder() - .AppendCenteredRotationDegrees(45F) + .AppendRotationDegrees(45F) .AppendScale(new SizeF(.25F, .25F)) .AppendTranslation(new PointF(10, 10)); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs index cbbf59caf5..e025851684 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs @@ -14,11 +14,15 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { protected override void AppendTranslation(AffineTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); protected override void AppendScale(AffineTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); - protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendCenteredRotationRadians(radians); + protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); + protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians, Vector2 center) => + builder.AppendRotationRadians(radians, center); protected override void PrependTranslation(AffineTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); protected override void PrependScale(AffineTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); - protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) => builder.PrependCenteredRotationRadians(radians); + protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians); + protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians, Vector2 center) => + builder.PrependRotationRadians(radians, center); protected override AffineTransformBuilder CreateBuilder(Rectangle rectangle) => new AffineTransformBuilder(); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index 0c167d7f97..ed6d3ef2bc 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { AffineTransformBuilder builder = new AffineTransformBuilder() - .AppendCenteredRotationDegrees(30); + .AppendRotationDegrees(30); image.Mutate(c => c.Transform(builder, resampler)); image.DebugSave(provider, resamplerName); @@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { image.DebugSave(provider, $"_original"); AffineTransformBuilder builder = new AffineTransformBuilder() - .AppendCenteredRotationDegrees(angleDeg) + .AppendRotationDegrees(angleDeg) .AppendScale(new SizeF(sx, sy)) .AppendTranslation(new PointF(tx, ty)); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { AffineTransformBuilder builder = new AffineTransformBuilder() - .AppendCenteredRotationDegrees(angleDeg) + .AppendRotationDegrees(angleDeg) .AppendScale(new SizeF(s, s)); image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic)); @@ -197,7 +197,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { AffineTransformBuilder builder = new AffineTransformBuilder() - .AppendCenteredRotationDegrees(50) + .AppendRotationDegrees(50) .AppendScale(new SizeF(.6F, .6F)); image.Mutate(i => i.Transform(builder, sampler)); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs index 14ed57033e..01448ac596 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs @@ -39,11 +39,15 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected override void AppendTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); protected override void AppendScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); - protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendCenteredRotationRadians(radians); + protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); + protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 center) => + builder.AppendRotationRadians(radians, center); protected override void PrependTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); protected override void PrependScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); - protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.PrependCenteredRotationRadians(radians); + protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians); + protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 center) => + builder.PrependRotationRadians(radians, center); protected override Vector2 Execute( ProjectiveTransformBuilder builder, diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs index 648ed5861f..badf430132 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs @@ -87,7 +87,12 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms [InlineData(200, 100, 10, 42, 84)] [InlineData(200, 100, 100, 42, 84)] [InlineData(100, 200, -10, 42, 84)] - public void RotateDegrees_ShouldCreateCenteredMatrix(int width, int height, float deg, float x, float y) + public void AppendRotationDegrees_WithoutSpecificRotationCenter_RotationIsCenteredAroundImageCenter( + int width, + int height, + float deg, + float x, + float y) { var size = new Size(width, height); TBuilder builder = this.CreateBuilder(size); @@ -97,13 +102,41 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms // TODO: We should also test CreateRotationMatrixDegrees() (and all TransformUtils stuff!) for correctness Matrix3x2 matrix = TransformUtils.CreateRotationMatrixDegrees(deg, size); - var position = new Vector2(x, y); + var position = new Vector2(x, y); var expected = Vector2.Transform(position, matrix); Vector2 actual = this.Execute(builder, new Rectangle(Point.Empty, size), position); Assert.Equal(actual, expected, Comparer); } - + + [Theory] + [InlineData(200, 100, 10, 30, 61, 42, 84)] + [InlineData(200, 100, 100, 30, 10, 20, 84)] + [InlineData(100, 200, -10, 30, 20, 11, 84)] + public void AppendRotationDegrees_WithRotationCenter( + int width, + int height, + float deg, + float cx, + float cy, + float x, + float y) + { + var size = new Size(width, height); + TBuilder builder = this.CreateBuilder(size); + + var centerPoint = new Vector2(cx, cy); + this.AppendRotationDegrees(builder, deg, centerPoint); + + var matrix = Matrix3x2.CreateRotation(ImageMaths.DegreesToRadians(deg), centerPoint); + + var position = new Vector2(x, y); + var expected = Vector2.Transform(position, matrix); + Vector2 actual = this.Execute(builder, new Rectangle(Point.Empty, size), position); + + Assert.Equal(actual, expected, Comparer); + } + [Fact] public void AppendPrependOpposite() { @@ -116,10 +149,12 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms // Forwards this.AppendRotationRadians(b1, pi); this.AppendScale(b1, new SizeF(2, 0.5f)); + this.AppendRotationRadians(b1, pi / 2, new Vector2(-0.5f, -0.1f)); this.AppendTranslation(b1, new PointF(123, 321)); // Backwards this.PrependTranslation(b2, new PointF(123, 321)); + this.PrependRotationRadians(b2, pi / 2, new Vector2(-0.5f, -0.1f)); this.PrependScale(b2, new SizeF(2, 0.5f)); this.PrependRotationRadians(b2, pi); @@ -152,14 +187,19 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected abstract void AppendTranslation(TBuilder builder, PointF translate); protected abstract void AppendScale(TBuilder builder, SizeF scale); protected abstract void AppendRotationRadians(TBuilder builder, float radians); + protected abstract void AppendRotationRadians(TBuilder builder, float radians, Vector2 center); protected abstract void PrependTranslation(TBuilder builder, PointF translate); protected abstract void PrependScale(TBuilder builder, SizeF scale); protected abstract void PrependRotationRadians(TBuilder builder, float radians); + protected abstract void PrependRotationRadians(TBuilder b1, float v, Vector2 vector2); protected virtual void AppendRotationDegrees(TBuilder builder, float degrees) => this.AppendRotationRadians(builder, ImageMaths.DegreesToRadians(degrees)); + protected virtual void AppendRotationDegrees(TBuilder builder, float degrees, Vector2 center) => + this.AppendRotationRadians(builder, ImageMaths.DegreesToRadians(degrees), center); + protected abstract Vector2 Execute(TBuilder builder, Rectangle rectangle, Vector2 sourcePoint); private static float Sqrt(float a) => (float)Math.Sqrt(a); From 0c9d6bbec115cd91448050bf8bc942ffb5c927fc Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 26 Nov 2018 16:11:38 +0100 Subject: [PATCH 353/381] printing ReferenceKernelMap --- .../KernelMapTests.ReferenceKernelMap.cs | 9 ++++- .../Processors/Transforms/KernelMapTests.cs | 39 +++++++++++++++---- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs index 932ea54948..cf0e94e8b4 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms /// /// Simplified reference implementation for functionality. /// - public class ReferenceKernelMap + internal class ReferenceKernelMap { private readonly ReferenceKernel[] kernels; @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } } - public struct ReferenceKernel + internal struct ReferenceKernel { public ReferenceKernel(int left, float[] values) { @@ -94,6 +94,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms public float[] Values { get; } public int Length => this.Values.Length; + + public static implicit operator ReferenceKernel(ResizeKernel orig) + { + return new ReferenceKernel(orig.Left, orig.GetValues().ToArray()); + } } } } \ 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 index 7abc1c3122..555ed15675 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { nameof(KnownResamplers.Lanczos3), 8, 6 }, // TODO: What's wrong here: - // { nameof(KnownResamplers.Lanczos3), 20, 12 }, + { nameof(KnownResamplers.Lanczos3), 20, 12 }, {nameof(KnownResamplers.Lanczos8), 500, 200 }, {nameof(KnownResamplers.Lanczos8), 100, 10 }, @@ -61,8 +61,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms var referenceMap = ReferenceKernelMap.Calculate(resampler, destSize, srcSize); #if DEBUG - string text = PrintKernelMap(kernelMap); - this.Output.WriteLine(text); + this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); + this.Output.WriteLine($"Reference KernelMap:\n{PrintKernelMap(referenceMap)}\n"); #endif for (int i = 0; i < kernelMap.DestinationSize; i++) @@ -73,19 +73,42 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms Assert.Equal(referenceKernel.Length, kernel.Length); Assert.Equal(referenceKernel.Left, kernel.Left); - Assert.True(kernel.GetValues().SequenceEqual(referenceKernel.Values)); + float[] expectedValues = referenceKernel.Values; + Span actualValues = kernel.GetValues(); + + Assert.Equal(expectedValues.Length, actualValues.Length); + + var comparer = new ApproximateFloatComparer(1e-6f); + + for (int x = 0; x < expectedValues.Length; x++) + { + Assert.True( + comparer.Equals(expectedValues[x], actualValues[x]), + $"{expectedValues[x]} != {actualValues[x]} @ (Row:{i}, Col:{x})"); + } } } - private static string PrintKernelMap(KernelMap kernelMap) + private static string PrintKernelMap(KernelMap kernelMap) => + PrintKernelMap(kernelMap, km => km.DestinationSize, (km, i) => km.GetKernel(i)); + + private static string PrintKernelMap(ReferenceKernelMap kernelMap) => + PrintKernelMap(kernelMap, km => km.DestinationSize, (km, i) => km.GetKernel(i)); + + private static string PrintKernelMap( + TKernelMap kernelMap, + Func getDestinationSize, + Func getKernel) { var bld = new StringBuilder(); - for (int i = 0; i < kernelMap.DestinationSize; i++) + int destinationSize = getDestinationSize(kernelMap); + + for (int i = 0; i < destinationSize; i++) { - ResizeKernel kernel = kernelMap.GetKernel(i); + ReferenceKernel kernel = getKernel(kernelMap, i); bld.Append($"({kernel.Left:D3}) || "); - Span span = kernel.GetValues(); + Span span = kernel.Values; for (int j = 0; j < kernel.Length; j++) { From eb82f9af683dc67e5b7d6c63f0d925273a640c38 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 26 Nov 2018 16:48:29 +0100 Subject: [PATCH 354/381] fixed a bug in KernelMap caused by overlapping memory areas --- .../Processors/Transforms/KernelMap.cs | 11 +++++++++-- .../Processors/Transforms/KernelMapTests.cs | 16 +++++++--------- .../Processing/Processors/Transforms/SkewTest.cs | 14 +------------- .../ImageSharp.Tests/TestUtilities/TestUtils.cs | 13 +++++++++++++ 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs index 3f984fef0d..3f2bf8dda4 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.periodicRegionMin = period + radius; this.periodicRegionMax = destinationSize - radius; - int width = radius * 2; + int width = (radius * 2) + 1; this.data = memoryAllocator.Allocate2D(width, destinationSize, AllocationOptions.Clean); this.kernels = new ResizeKernel[destinationSize]; } @@ -141,8 +141,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// private ResizeKernel CreateKernel(int destIdx, int left, int rightIdx) { - int flatStartIndex = destIdx * this.data.Width; int length = rightIdx - left + 1; + + if (length > this.data.Width) + { + throw new InvalidOperationException($"Error in KernelMap.CreateKernel({destIdx},{left},{rightIdx}): left > this.data.Width"); + } + + int flatStartIndex = destIdx * this.data.Width; + Memory bufferSlice = this.data.Memory.Slice(flatStartIndex, length); return new ResizeKernel(left, bufferSlice); } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index 555ed15675..c5916ce0be 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Runtime.InteropServices; using System.Text; using SixLabors.ImageSharp.PixelFormats; @@ -40,25 +41,22 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { nameof(KnownResamplers.Lanczos3), 9, 12 }, { nameof(KnownResamplers.Lanczos3), 6, 8 }, { nameof(KnownResamplers.Lanczos3), 8, 6 }, - - // TODO: What's wrong here: { nameof(KnownResamplers.Lanczos3), 20, 12 }, - {nameof(KnownResamplers.Lanczos8), 500, 200 }, - {nameof(KnownResamplers.Lanczos8), 100, 10 }, - {nameof(KnownResamplers.Lanczos8), 100, 80 }, - {nameof(KnownResamplers.Lanczos8), 10, 100 }, + { nameof(KnownResamplers.Lanczos8), 500, 200 }, + { nameof(KnownResamplers.Lanczos8), 100, 10 }, + { nameof(KnownResamplers.Lanczos8), 100, 80 }, + { nameof(KnownResamplers.Lanczos8), 10, 100 }, }; [Theory] [MemberData(nameof(KernelMapData))] public void KernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) { - var resampler = (IResampler)typeof(KnownResamplers).GetProperty(resamplerName).GetValue(null); - - var kernelMap = KernelMap.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator); + IResampler resampler = TestUtils.GetResampler(resamplerName); var referenceMap = ReferenceKernelMap.Calculate(resampler, destSize, srcSize); + var kernelMap = KernelMap.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator); #if DEBUG this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/SkewTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/SkewTest.cs index d1d2ea0771..29c51543fc 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/SkewTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/SkewTest.cs @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { foreach (string resamplerName in ResamplerNames) { - IResampler sampler = GetResampler(resamplerName); + IResampler sampler = TestUtils.GetResampler(resamplerName); using (Image image = provider.GetImage()) { image.Mutate(i => i.Skew(x, y, sampler)); @@ -68,17 +68,5 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } } } - - private static IResampler GetResampler(string name) - { - PropertyInfo property = typeof(KnownResamplers).GetTypeInfo().GetProperty(name); - - if (property is null) - { - throw new Exception($"No resampler named '{name}"); - } - - return (IResampler)property.GetValue(null); - } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs index d7755ff7a4..5ea0bccf06 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs @@ -10,6 +10,7 @@ using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using SixLabors.Primitives; @@ -284,5 +285,17 @@ namespace SixLabors.ImageSharp.Tests } public static string AsInvariantString(this FormattableString formattable) => System.FormattableString.Invariant(formattable); + + public static IResampler GetResampler(string name) + { + PropertyInfo property = typeof(KnownResamplers).GetTypeInfo().GetProperty(name); + + if (property is null) + { + throw new Exception($"No resampler named '{name}"); + } + + return (IResampler)property.GetValue(null); + } } } \ No newline at end of file From 5d034d5fc0f51d593a7ae2b7a3b827308d3b9415 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 26 Nov 2018 18:16:47 +0000 Subject: [PATCH 355/381] Use existing method. (There's precedence) --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 14 +------------- .../Processing/AffineTransformBuilder.cs | 4 ++-- .../Processing/ProjectiveTransformBuilder.cs | 5 ++--- 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index c0c8e07e6f..8720140e13 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -125,19 +125,7 @@ namespace SixLabors.ImageSharp /// should be power of 2. /// [MethodImpl(InliningOptions.ShortMethod)] - public static int ModuloP2(int x, int m) - { - return x & (m - 1); - } - - /// - /// Converts degrees to radians - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static float DegreesToRadians(float degrees) - { - return degrees * ((float)Math.PI / 180f); - } + public static int ModuloP2(int x, int m) => x & (m - 1); /// /// Returns the absolute value of a 32-bit signed integer. Uses bit shifting to speed up the operation. diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index eab75cfdbe..a91d1f0d2a 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in degrees. /// The . public AffineTransformBuilder PrependRotationDegrees(float degrees) - => this.PrependRotationRadians(ImageMaths.DegreesToRadians(degrees)); + => this.PrependRotationRadians(MathFExtensions.DegreeToRadian(degrees)); /// /// Appends a rotation matrix using the given rotation angle in degrees @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in degrees. /// The . public AffineTransformBuilder AppendRotationDegrees(float degrees) - => this.AppendRotationRadians(ImageMaths.DegreesToRadians(degrees)); + => this.AppendRotationRadians(MathFExtensions.DegreeToRadian(degrees)); /// /// Prepends a scale matrix from the given uniform scale. diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index 8bde90d51a..ad6ef20bb1 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.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; using SixLabors.ImageSharp.Processing.Processors.Transforms; @@ -115,7 +114,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in degrees. /// The . public ProjectiveTransformBuilder PrependCenteredRotationDegrees(float degrees) - => this.PrependRotationRadians(ImageMaths.DegreesToRadians(degrees)); + => this.PrependRotationRadians(MathFExtensions.DegreeToRadian(degrees)); /// /// Appends a centered rotation matrix using the given rotation in degrees. @@ -123,7 +122,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in degrees. /// The . public ProjectiveTransformBuilder AppendRotationDegrees(float degrees) - => this.AppendRotationRadians(ImageMaths.DegreesToRadians(degrees)); + => this.AppendRotationRadians(MathFExtensions.DegreeToRadian(degrees)); /// /// Prepends a scale matrix from the given uniform scale. From cfa7cfd3db4ecdd9d62e7ae14cfc4221dca99473 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 26 Nov 2018 18:22:39 +0000 Subject: [PATCH 356/381] Remove "Matrix" suffix --- src/ImageSharp/Processing/ProjectiveTransformBuilder.cs | 4 ++-- .../Processing/Transforms/ProjectiveTransformTests.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index ad6ef20bb1..dff9bc6d94 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.Processing /// An enumeration that indicates on which corners to taper the rectangle. /// The amount to taper. /// The . - public ProjectiveTransformBuilder PrependTaperMatrix(TaperSide side, TaperCorner corner, float fraction) + public ProjectiveTransformBuilder PrependTaper(TaperSide side, TaperCorner corner, float fraction) => this.PrependMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); /// @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Processing /// An enumeration that indicates on which corners to taper the rectangle. /// The amount to taper. /// The . - public ProjectiveTransformBuilder AppendTaperMatrix(TaperSide side, TaperCorner corner, float fraction) + public ProjectiveTransformBuilder AppendTaper(TaperSide side, TaperCorner corner, float fraction) => this.AppendMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); /// diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs index 0362d75a0b..9436b7828c 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder(image.Size()) - .AppendTaperMatrix(TaperSide.Right, TaperCorner.Both, .5F); + .AppendTaper(TaperSide.Right, TaperCorner.Both, .5F); image.Mutate(i => i.Transform(builder, sampler)); @@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder(image.Size()) - .AppendTaperMatrix(taperSide, taperCorner, .5F); + .AppendTaper(taperSide, taperCorner, .5F); image.Mutate(i => i.Transform(builder)); From ffba817bcae3a2895534c037798bf8e30232e06d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 26 Nov 2018 22:59:31 +0000 Subject: [PATCH 357/381] Update dependencies --- src/ImageSharp.Drawing/ImageSharp.Drawing.csproj | 4 ++-- .../Converters/CIeLchToCieLabConverter.cs | 2 +- .../Converters/CieLabToCieLchConverter.cs | 2 +- .../Converters/CieLchuvToCieLuvConverter.cs | 2 +- .../Converters/CieLuvToCieLchuvConverter.cs | 2 +- src/ImageSharp/ImageSharp.csproj | 2 +- src/ImageSharp/Processing/AffineTransformBuilder.cs | 4 ++-- src/ImageSharp/Processing/KnownFilterMatrices.cs | 2 +- .../Processing/ProjectiveTransformBuilder.cs | 9 ++------- .../Processing/Transforms/TransformBuilderTestBase.cs | 10 ++++------ 10 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index 1cb3f444f0..ae5069be1d 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -38,8 +38,8 @@ - - + + All diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs index dd352db809..40d8c5bc69 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation // Conversion algorithm described here: // https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC float l = input.L, c = input.C, hDegrees = input.H; - float hRadians = MathFExtensions.DegreeToRadian(hDegrees); + float hRadians = GeometryUtilities.DegreeToRadian(hDegrees); float a = c * MathF.Cos(hRadians); float b = c * MathF.Sin(hRadians); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs index 81196604e5..2b859205a0 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation float l = input.L, a = input.A, b = input.B; float c = MathF.Sqrt((a * a) + (b * b)); float hRadians = MathF.Atan2(b, a); - float hDegrees = MathFExtensions.RadianToDegree(hRadians); + float hDegrees = GeometryUtilities.RadianToDegree(hRadians); // Wrap the angle round at 360. hDegrees %= 360; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs index 4f5a20bec7..ba5b8bfb79 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation // Conversion algorithm described here: // https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29 float l = input.L, c = input.C, hDegrees = input.H; - float hRadians = MathFExtensions.DegreeToRadian(hDegrees); + float hRadians = GeometryUtilities.DegreeToRadian(hDegrees); float u = c * MathF.Cos(hRadians); float v = c * MathF.Sin(hRadians); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs index 297c18c5c3..3c7d356a5e 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation float l = input.L, a = input.U, b = input.V; float c = MathF.Sqrt((a * a) + (b * b)); float hRadians = MathF.Atan2(b, a); - float hDegrees = MathFExtensions.RadianToDegree(hRadians); + float hDegrees = GeometryUtilities.RadianToDegree(hRadians); // Wrap the angle round at 360. hDegrees %= 360; diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 29d29d50d8..c19c92426f 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -42,7 +42,7 @@ - + All diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index a91d1f0d2a..ed5aa987f4 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in degrees. /// The . public AffineTransformBuilder PrependRotationDegrees(float degrees) - => this.PrependRotationRadians(MathFExtensions.DegreeToRadian(degrees)); + => this.PrependRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); /// /// Appends a rotation matrix using the given rotation angle in degrees @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in degrees. /// The . public AffineTransformBuilder AppendRotationDegrees(float degrees) - => this.AppendRotationRadians(MathFExtensions.DegreeToRadian(degrees)); + => this.AppendRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); /// /// Prepends a scale matrix from the given uniform scale. diff --git a/src/ImageSharp/Processing/KnownFilterMatrices.cs b/src/ImageSharp/Processing/KnownFilterMatrices.cs index 4f5e3c8697..cf0d19ff85 100644 --- a/src/ImageSharp/Processing/KnownFilterMatrices.cs +++ b/src/ImageSharp/Processing/KnownFilterMatrices.cs @@ -322,7 +322,7 @@ namespace SixLabors.ImageSharp.Processing degrees += 360; } - float radian = MathFExtensions.DegreeToRadian(degrees); + float radian = GeometryUtilities.DegreeToRadian(degrees); float cosRadian = MathF.Cos(radian); float sinRadian = MathF.Sin(radian); diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index dff9bc6d94..750f2f5d0e 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -114,7 +114,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in degrees. /// The . public ProjectiveTransformBuilder PrependCenteredRotationDegrees(float degrees) - => this.PrependRotationRadians(MathFExtensions.DegreeToRadian(degrees)); + => this.PrependRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); /// /// Appends a centered rotation matrix using the given rotation in degrees. @@ -122,7 +122,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in degrees. /// The . public ProjectiveTransformBuilder AppendRotationDegrees(float degrees) - => this.AppendRotationRadians(MathFExtensions.DegreeToRadian(degrees)); + => this.AppendRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); /// /// Prepends a scale matrix from the given uniform scale. @@ -247,10 +247,5 @@ namespace SixLabors.ImageSharp.Processing return matrix; } - - /// - /// Removes all matrices from the builder. - /// - public void Clear() => this.matrices.Clear(); } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs index badf430132..dffa3c7ac6 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs @@ -3,8 +3,6 @@ using System; using System.Numerics; - -using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.Primitives; @@ -128,7 +126,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms var centerPoint = new Vector2(cx, cy); this.AppendRotationDegrees(builder, deg, centerPoint); - var matrix = Matrix3x2.CreateRotation(ImageMaths.DegreesToRadians(deg), centerPoint); + var matrix = Matrix3x2.CreateRotation(GeometryUtilities.DegreeToRadian(deg), centerPoint); var position = new Vector2(x, y); var expected = Vector2.Transform(position, matrix); @@ -195,13 +193,13 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected abstract void PrependRotationRadians(TBuilder b1, float v, Vector2 vector2); protected virtual void AppendRotationDegrees(TBuilder builder, float degrees) => - this.AppendRotationRadians(builder, ImageMaths.DegreesToRadians(degrees)); + this.AppendRotationRadians(builder, GeometryUtilities.DegreeToRadian(degrees)); protected virtual void AppendRotationDegrees(TBuilder builder, float degrees, Vector2 center) => - this.AppendRotationRadians(builder, ImageMaths.DegreesToRadians(degrees), center); + this.AppendRotationRadians(builder, GeometryUtilities.DegreeToRadian(degrees), center); protected abstract Vector2 Execute(TBuilder builder, Rectangle rectangle, Vector2 sourcePoint); - + private static float Sqrt(float a) => (float)Math.Sqrt(a); } } \ No newline at end of file From 7ea99129b5745fd780b11d4f84a959d1cdb5c406 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 27 Nov 2018 00:46:32 +0000 Subject: [PATCH 358/381] Match APIs --- .../Processing/AffineTransformBuilder.cs | 114 +++++----- .../ProjectiveTransformProcessor.cs | 6 +- .../Processing/ProjectiveTransformBuilder.cs | 210 ++++++++---------- .../Processing/TransformExtensions.cs | 96 +++++--- .../Transforms/AffineTransformBuilderTests.cs | 15 +- .../ProjectiveTransformBuilderTests.cs | 40 +--- .../Transforms/ProjectiveTransformTests.cs | 6 +- .../Transforms/TransformBuilderTestBase.cs | 12 +- 8 files changed, 246 insertions(+), 253 deletions(-) diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index ed5aa987f4..29c37d7bf0 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -17,22 +17,13 @@ namespace SixLabors.ImageSharp.Processing private readonly List> matrixFactories = new List>(); /// - /// Prepends a centered rotation matrix using the given rotation in radians. - /// - /// The amount of rotation, in radians. - /// The rotation center point - /// The . - public AffineTransformBuilder PrependRotationRadians(float radians, Vector2 centerPoint) - => this.PrependMatrix(Matrix3x2.CreateRotation(radians, centerPoint)); - - /// - /// Appends a centered rotation matrix using the given rotation in radians. + /// Prepends a rotation matrix using the given rotation angle in degrees + /// and the image center point as rotation center. /// - /// The amount of rotation, in radians. - /// The rotation center point + /// The amount of rotation, in degrees. /// The . - public AffineTransformBuilder AppendRotationRadians(float radians, Vector2 centerPoint) - => this.AppendMatrix(Matrix3x2.CreateRotation(radians, centerPoint)); + public AffineTransformBuilder PrependRotationDegrees(float degrees) + => this.PrependRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); /// /// Prepends a rotation matrix using the given rotation angle in radians @@ -44,31 +35,40 @@ namespace SixLabors.ImageSharp.Processing => this.Prepend(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); /// - /// Appends a rotation matrix using the given rotation angle in radians - /// and the image center point as rotation center. + /// Prepends a centered rotation matrix using the given rotation in radians. /// /// The amount of rotation, in radians. + /// The rotation origin point. /// The . - public AffineTransformBuilder AppendRotationRadians(float radians) - => this.Append(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); + public AffineTransformBuilder PrependRotationRadians(float radians, Vector2 origin) + => this.PrependMatrix(Matrix3x2.CreateRotation(radians, origin)); /// - /// Prepends a rotation matrix using the given rotation angle in degrees + /// Appends a rotation matrix using the given rotation angle in degrees /// and the image center point as rotation center. /// /// The amount of rotation, in degrees. /// The . - public AffineTransformBuilder PrependRotationDegrees(float degrees) - => this.PrependRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); + public AffineTransformBuilder AppendRotationDegrees(float degrees) + => this.AppendRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); /// - /// Appends a rotation matrix using the given rotation angle in degrees + /// Appends a rotation matrix using the given rotation angle in radians /// and the image center point as rotation center. /// - /// The amount of rotation, in degrees. + /// The amount of rotation, in radians. /// The . - public AffineTransformBuilder AppendRotationDegrees(float degrees) - => this.AppendRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); + public AffineTransformBuilder AppendRotationRadians(float radians) + => this.Append(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); + + /// + /// Appends a centered rotation matrix using the given rotation in radians. + /// + /// The amount of rotation, in radians. + /// The rotation origin point. + /// The . + public AffineTransformBuilder AppendRotationRadians(float radians, Vector2 origin) + => this.AppendMatrix(Matrix3x2.CreateRotation(radians, origin)); /// /// Prepends a scale matrix from the given uniform scale. @@ -79,12 +79,12 @@ namespace SixLabors.ImageSharp.Processing => this.PrependMatrix(Matrix3x2.CreateScale(scale)); /// - /// Appends a scale matrix from the given uniform scale. + /// Prepends a scale matrix from the given vector scale. /// - /// The uniform scale. + /// The horizontal and vertical scale. /// The . - public AffineTransformBuilder AppendScale(float scale) - => this.AppendMatrix(Matrix3x2.CreateScale(scale)); + public AffineTransformBuilder PrependScale(SizeF scale) + => this.PrependScale((Vector2)scale); /// /// Prepends a scale matrix from the given vector scale. @@ -95,28 +95,28 @@ namespace SixLabors.ImageSharp.Processing => this.PrependMatrix(Matrix3x2.CreateScale(scales)); /// - /// Appends a scale matrix from the given vector scale. + /// Appends a scale matrix from the given uniform scale. /// - /// The horizontal and vertical scale. + /// The uniform scale. /// The . - public AffineTransformBuilder AppendScale(Vector2 scales) - => this.AppendMatrix(Matrix3x2.CreateScale(scales)); + public AffineTransformBuilder AppendScale(float scale) + => this.AppendMatrix(Matrix3x2.CreateScale(scale)); /// - /// Prepends a scale matrix from the given vector scale. + /// Appends a scale matrix from the given vector scale. /// - /// The horizontal and vertical scale. + /// The horizontal and vertical scale. /// The . - public AffineTransformBuilder PrependScale(SizeF scale) - => this.PrependScale((Vector2)scale); + public AffineTransformBuilder AppendScale(SizeF scales) + => this.AppendScale((Vector2)scales); /// /// Appends a scale matrix from the given vector scale. /// /// The horizontal and vertical scale. /// The . - public AffineTransformBuilder AppendScale(SizeF scales) - => this.AppendScale((Vector2)scales); + public AffineTransformBuilder AppendScale(Vector2 scales) + => this.AppendMatrix(Matrix3x2.CreateScale(scales)); /// /// Prepends a centered skew matrix from the give angles in degrees. @@ -141,66 +141,58 @@ namespace SixLabors.ImageSharp.Processing /// /// The translation position. /// The . - public AffineTransformBuilder PrependTranslation(Vector2 position) - => this.PrependMatrix(Matrix3x2.CreateTranslation(position)); + public AffineTransformBuilder PrependTranslation(PointF position) + => this.PrependTranslation((Vector2)position); /// - /// Appends a translation matrix from the given vector. + /// Prepends a translation matrix from the given vector. /// /// The translation position. /// The . - public AffineTransformBuilder AppendTranslation(Vector2 position) - => this.AppendMatrix(Matrix3x2.CreateTranslation(position)); + public AffineTransformBuilder PrependTranslation(Vector2 position) + => this.PrependMatrix(Matrix3x2.CreateTranslation(position)); /// - /// Prepends a translation matrix from the given vector. + /// Appends a translation matrix from the given vector. /// /// The translation position. /// The . - public AffineTransformBuilder PrependTranslation(PointF position) - => this.PrependTranslation((Vector2)position); + public AffineTransformBuilder AppendTranslation(PointF position) + => this.AppendTranslation((Vector2)position); /// /// Appends a translation matrix from the given vector. /// /// The translation position. /// The . - public AffineTransformBuilder AppendTranslation(PointF position) - => this.AppendTranslation((Vector2)position); + public AffineTransformBuilder AppendTranslation(Vector2 position) + => this.AppendMatrix(Matrix3x2.CreateTranslation(position)); /// /// Prepends a raw matrix. /// /// The matrix to prepend. /// The . - public AffineTransformBuilder PrependMatrix(Matrix3x2 matrix) - { - this.matrixFactories.Insert(0, _ => matrix); - return this; - } + public AffineTransformBuilder PrependMatrix(Matrix3x2 matrix) => this.Prepend(_ => matrix); /// /// Appends a raw matrix. /// /// The matrix to append. /// The . - public AffineTransformBuilder AppendMatrix(Matrix3x2 matrix) - { - this.matrixFactories.Add(_ => matrix); - return this; - } + public AffineTransformBuilder AppendMatrix(Matrix3x2 matrix) => this.Append(_ => matrix); /// /// Returns the combined matrix for a given source size. /// - /// The source image size + /// The source image size. /// The . public Matrix3x2 BuildMatrix(Size sourceSize) => this.BuildMatrix(new Rectangle(Point.Empty, sourceSize)); /// /// Returns the combined matrix for a given source rectangle. /// - /// The rectangle in the source image + /// The rectangle in the source image. /// The . public Matrix3x2 BuildMatrix(Rectangle sourceRectangle) { diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index bfde1769c1..273156e2eb 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -24,13 +24,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// The transform matrix. /// The sampler to perform the transform operation. - /// The source image size. - public ProjectiveTransformProcessor(Matrix4x4 matrix, IResampler sampler, Size sourceSize) + /// The target dimensions. + public ProjectiveTransformProcessor(Matrix4x4 matrix, IResampler sampler, Size targetDimensions) { Guard.NotNull(sampler, nameof(sampler)); this.Sampler = sampler; this.TransformMatrix = matrix; - this.TargetDimensions = TransformUtils.GetTransformedSize(sourceSize, matrix); + this.TargetDimensions = targetDimensions; } /// diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index 750f2f5d0e..a905467bba 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.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 System.Numerics; using SixLabors.ImageSharp.Processing.Processors.Transforms; @@ -13,34 +14,7 @@ namespace SixLabors.ImageSharp.Processing /// public class ProjectiveTransformBuilder { - private readonly List matrices = new List(); - private Rectangle sourceRectangle; - - /// - /// Initializes a new instance of the class. - /// - /// The source image size. - public ProjectiveTransformBuilder(Size sourceSize) - : this(new Rectangle(Point.Empty, sourceSize)) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The source rectangle. - public ProjectiveTransformBuilder(Rectangle sourceRectangle) - { - Guard.MustBeGreaterThan(sourceRectangle.Width, 0, nameof(sourceRectangle)); - Guard.MustBeGreaterThan(sourceRectangle.Height, 0, nameof(sourceRectangle)); - - this.sourceRectangle = sourceRectangle; - } - - /// - /// Gets the source image size. - /// - internal Size Size => this.sourceRectangle.Size; + private readonly List> matrixFactories = new List>(); /// /// Prepends a matrix that performs a tapering projective transform. @@ -50,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount to taper. /// The . public ProjectiveTransformBuilder PrependTaper(TaperSide side, TaperCorner corner, float fraction) - => this.PrependMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); + => this.Prepend(size => TransformUtils.CreateTaperMatrix(size, side, corner, fraction)); /// /// Appends a matrix that performs a tapering projective transform. @@ -60,7 +34,15 @@ namespace SixLabors.ImageSharp.Processing /// The amount to taper. /// The . public ProjectiveTransformBuilder AppendTaper(TaperSide side, TaperCorner corner, float fraction) - => this.AppendMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); + => this.Append(size => TransformUtils.CreateTaperMatrix(size, side, corner, fraction)); + + /// + /// Prepends a centered rotation matrix using the given rotation in degrees. + /// + /// The amount of rotation, in degrees. + /// The . + public ProjectiveTransformBuilder PrependRotationDegrees(float degrees) + => this.PrependRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); /// /// Prepends a centered rotation matrix using the given rotation in radians. @@ -68,33 +50,32 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in radians. /// The . public ProjectiveTransformBuilder PrependRotationRadians(float radians) - { - var m = new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); - return this.PrependMatrix(m); - } + => this.Prepend(size => new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, size))); /// /// Appends a centered rotation matrix using the given rotation in radians. /// /// The amount of rotation, in radians. + /// The rotation center. /// The . - public ProjectiveTransformBuilder AppendRotationRadians(float radians) - { - var m = new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); - return this.AppendMatrix(m); - } + internal ProjectiveTransformBuilder PrependRotationRadians(float radians, Vector2 centerPoint) + => this.PrependMatrix(Matrix4x4.CreateRotationZ(radians, new Vector3(centerPoint, 0))); + + /// + /// Appends a centered rotation matrix using the given rotation in degrees. + /// + /// The amount of rotation, in degrees. + /// The . + public ProjectiveTransformBuilder AppendRotationDegrees(float degrees) + => this.AppendRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); /// /// Appends a centered rotation matrix using the given rotation in radians. /// /// The amount of rotation, in radians. - /// The rotation center. /// The . - internal ProjectiveTransformBuilder PrependRotationRadians(float radians, Vector2 centerPoint) - { - var m = Matrix4x4.CreateRotationZ(radians, new Vector3(centerPoint, 0)); - return this.PrependMatrix(m); - } + public ProjectiveTransformBuilder AppendRotationRadians(float radians) + => this.Append(size => new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, size))); /// /// Appends a centered rotation matrix using the given rotation in radians. @@ -103,80 +84,69 @@ namespace SixLabors.ImageSharp.Processing /// The rotation center. /// The . internal ProjectiveTransformBuilder AppendRotationRadians(float radians, Vector2 centerPoint) - { - var m = Matrix4x4.CreateRotationZ(radians, new Vector3(centerPoint, 0)); - return this.AppendMatrix(m); - } + => this.AppendMatrix(Matrix4x4.CreateRotationZ(radians, new Vector3(centerPoint, 0))); /// - /// Prepends a centered rotation matrix using the given rotation in degrees. + /// Prepends a scale matrix from the given uniform scale. /// - /// The amount of rotation, in degrees. - /// The . - public ProjectiveTransformBuilder PrependCenteredRotationDegrees(float degrees) - => this.PrependRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); + /// The uniform scale. + /// The . + public ProjectiveTransformBuilder PrependScale(float scale) + => this.PrependMatrix(Matrix4x4.CreateScale(scale)); /// - /// Appends a centered rotation matrix using the given rotation in degrees. + /// Prepends a scale matrix from the given vector scale. /// - /// The amount of rotation, in degrees. - /// The . - public ProjectiveTransformBuilder AppendRotationDegrees(float degrees) - => this.AppendRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); + /// The horizontal and vertical scale. + /// The . + public ProjectiveTransformBuilder PrependScale(SizeF scale) + => this.PrependScale((Vector2)scale); /// - /// Prepends a scale matrix from the given uniform scale. + /// Prepends a scale matrix from the given vector scale. /// - /// The uniform scale. - /// The . - public ProjectiveTransformBuilder PrependScale(float scale) - => this.PrependMatrix(Matrix4x4.CreateScale(scale)); + /// The horizontal and vertical scale. + /// The . + public ProjectiveTransformBuilder PrependScale(Vector2 scales) + => this.PrependMatrix(Matrix4x4.CreateScale(new Vector3(scales, 1F))); /// /// Appends a scale matrix from the given uniform scale. /// /// The uniform scale. - /// The . + /// The . public ProjectiveTransformBuilder AppendScale(float scale) => this.AppendMatrix(Matrix4x4.CreateScale(scale)); /// - /// Prepends a scale matrix from the given vector scale. + /// Appends a scale matrix from the given vector scale. /// /// The horizontal and vertical scale. - /// The . - public ProjectiveTransformBuilder PrependScale(Vector2 scales) - => this.PrependMatrix(Matrix4x4.CreateScale(new Vector3(scales, 1f))); + /// The . + public ProjectiveTransformBuilder AppendScale(SizeF scales) + => this.AppendScale((Vector2)scales); /// /// Appends a scale matrix from the given vector scale. /// /// The horizontal and vertical scale. - /// The . + /// The . public ProjectiveTransformBuilder AppendScale(Vector2 scales) - => this.AppendMatrix(Matrix4x4.CreateScale(new Vector3(scales, 1f))); - - /// - /// Prepends a scale matrix from the given vector scale. - /// - /// The horizontal and vertical scale. - /// The . - public ProjectiveTransformBuilder PrependScale(SizeF scale) - => this.PrependScale((Vector2)scale); + => this.AppendMatrix(Matrix4x4.CreateScale(new Vector3(scales, 1F))); /// - /// Appends a scale matrix from the given vector scale. + /// Prepends a translation matrix from the given vector. /// - /// The horizontal and vertical scale. - /// The . - public ProjectiveTransformBuilder AppendScale(SizeF scales) - => this.AppendScale((Vector2)scales); + /// The translation position. + /// The . + public ProjectiveTransformBuilder PrependTranslation(PointF position) + => this.PrependTranslation((Vector2)position); /// /// Prepends a translation matrix from the given vector. /// /// The translation position. - /// The . + /// The . public ProjectiveTransformBuilder PrependTranslation(Vector2 position) => this.PrependMatrix(Matrix4x4.CreateTranslation(new Vector3(position, 0))); @@ -184,68 +154,72 @@ namespace SixLabors.ImageSharp.Processing /// Appends a translation matrix from the given vector. /// /// The translation position. - /// The . - public ProjectiveTransformBuilder AppendTranslation(Vector2 position) - => this.AppendMatrix(Matrix4x4.CreateTranslation(new Vector3(position, 0))); - - /// - /// Prepends a translation matrix from the given vector. - /// - /// The translation position. - /// The . - public ProjectiveTransformBuilder PrependTranslation(PointF position) - => this.PrependTranslation((Vector2)position); + /// The . + public ProjectiveTransformBuilder AppendTranslation(PointF position) + => this.AppendTranslation((Vector2)position); /// /// Appends a translation matrix from the given vector. /// /// The translation position. - /// The . - public ProjectiveTransformBuilder AppendTranslation(PointF position) - => this.AppendTranslation((Vector2)position); + /// The . + public ProjectiveTransformBuilder AppendTranslation(Vector2 position) + => this.AppendMatrix(Matrix4x4.CreateTranslation(new Vector3(position, 0))); /// /// Prepends a raw matrix. /// /// The matrix to prepend. /// The . - public ProjectiveTransformBuilder PrependMatrix(Matrix4x4 matrix) - { - this.matrices.Insert(0, matrix); - return this; - } + public ProjectiveTransformBuilder PrependMatrix(Matrix4x4 matrix) => this.Prepend(_ => matrix); /// /// Appends a raw matrix. /// /// The matrix to append. /// The . - public ProjectiveTransformBuilder AppendMatrix(Matrix4x4 matrix) - { - this.matrices.Add(matrix); - return this; - } + public ProjectiveTransformBuilder AppendMatrix(Matrix4x4 matrix) => this.Append(_ => matrix); + + /// + /// Returns the combined matrix for a given source size. + /// + /// The source image size. + /// The . + public Matrix4x4 BuildMatrix(Size sourceSize) => this.BuildMatrix(new Rectangle(Point.Empty, sourceSize)); /// - /// Returns the combined matrix. + /// Returns the combined matrix for a given source rectangle. /// + /// The rectangle in the source image. /// The . - public Matrix4x4 BuildMatrix() + public Matrix4x4 BuildMatrix(Rectangle sourceRectangle) { - Matrix4x4 matrix = Matrix4x4.Identity; + Guard.MustBeGreaterThan(sourceRectangle.Width, 0, nameof(sourceRectangle)); + Guard.MustBeGreaterThan(sourceRectangle.Height, 0, nameof(sourceRectangle)); // Translate the origin matrix to cater for source rectangle offsets. - if (!this.sourceRectangle.Equals(default)) - { - matrix *= Matrix4x4.CreateTranslation(new Vector3(-this.sourceRectangle.Location, 0)); - } + var matrix = Matrix4x4.CreateTranslation(new Vector3(-sourceRectangle.Location, 0)); + + Size size = sourceRectangle.Size; - foreach (Matrix4x4 m in this.matrices) + foreach (Func factory in this.matrixFactories) { - matrix *= m; + matrix *= factory(size); } return matrix; } + + private ProjectiveTransformBuilder Prepend(Func factory) + { + this.matrixFactories.Insert(0, factory); + return this; + } + + private ProjectiveTransformBuilder Append(Func factory) + { + this.matrixFactories.Add(factory); + return this; + } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/TransformExtensions.cs b/src/ImageSharp/Processing/TransformExtensions.cs index de4a3e5ba7..db14b6baf9 100644 --- a/src/ImageSharp/Processing/TransformExtensions.cs +++ b/src/ImageSharp/Processing/TransformExtensions.cs @@ -15,40 +15,32 @@ namespace SixLabors.ImageSharp.Processing public static class TransformExtensions { /// - /// Performs an affine transform of an image using the specified sampling algorithm. + /// Performs an affine transform of an image. /// /// The pixel format. - /// The . - /// The source rectangle - /// The transformation matrix. - /// The size of the result image. - /// The to perform the resampling. + /// The image to transform. + /// The affine transform builder. /// The public static IImageProcessingContext Transform( - this IImageProcessingContext ctx, - Rectangle sourceRectangle, - Matrix3x2 transform, - Size targetDimensions, - IResampler sampler) + this IImageProcessingContext source, + AffineTransformBuilder builder) where TPixel : struct, IPixel - { - return ctx.ApplyProcessor( - new AffineTransformProcessor(transform, sampler, targetDimensions), - sourceRectangle); - } + => Transform(source, builder, KnownResamplers.Bicubic); /// - /// Performs an affine transform of an image. + /// Performs an affine transform of an image using the specified sampling algorithm. /// /// The pixel format. - /// The image to transform. + /// The . /// The affine transform builder. + /// The to perform the resampling. /// The public static IImageProcessingContext Transform( - this IImageProcessingContext source, - AffineTransformBuilder builder) + this IImageProcessingContext ctx, + AffineTransformBuilder builder, + IResampler sampler) where TPixel : struct, IPixel - => Transform(source, builder, KnownResamplers.Bicubic); + => ctx.Transform(new Rectangle(Point.Empty, ctx.GetCurrentSize()), builder, sampler); /// /// Performs an affine transform of an image using the specified sampling algorithm. @@ -76,16 +68,22 @@ namespace SixLabors.ImageSharp.Processing /// /// The pixel format. /// The . - /// The affine transform builder. + /// The source rectangle + /// The transformation matrix. + /// The size of the result image. /// The to perform the resampling. /// The public static IImageProcessingContext Transform( this IImageProcessingContext ctx, - AffineTransformBuilder builder, + Rectangle sourceRectangle, + Matrix3x2 transform, + Size targetDimensions, IResampler sampler) where TPixel : struct, IPixel { - return ctx.Transform(new Rectangle(Point.Empty, ctx.GetCurrentSize()), builder, sampler); + return ctx.ApplyProcessor( + new AffineTransformProcessor(transform, sampler, targetDimensions), + sourceRectangle); } /// @@ -105,15 +103,59 @@ namespace SixLabors.ImageSharp.Processing /// Performs a projective transform of an image using the specified sampling algorithm. /// /// The pixel format. - /// The image to transform. + /// The . /// The projective transform builder. /// The to perform the resampling. /// The public static IImageProcessingContext Transform( - this IImageProcessingContext source, + this IImageProcessingContext ctx, + ProjectiveTransformBuilder builder, + IResampler sampler) + where TPixel : struct, IPixel + => ctx.Transform(new Rectangle(Point.Empty, ctx.GetCurrentSize()), builder, sampler); + + /// + /// Performs a projective transform of an image using the specified sampling algorithm. + /// + /// The pixel format. + /// The . + /// The source rectangle + /// The projective transform builder. + /// The to perform the resampling. + /// The + public static IImageProcessingContext Transform( + this IImageProcessingContext ctx, + Rectangle sourceRectangle, ProjectiveTransformBuilder builder, IResampler sampler) where TPixel : struct, IPixel - => source.ApplyProcessor(new ProjectiveTransformProcessor(builder.BuildMatrix(), sampler, builder.Size)); + { + Matrix4x4 transform = builder.BuildMatrix(sourceRectangle); + Size targetDimensions = TransformUtils.GetTransformedSize(sourceRectangle.Size, transform); + return ctx.Transform(sourceRectangle, transform, targetDimensions, sampler); + } + + /// + /// Performs a projective transform of an image using the specified sampling algorithm. + /// + /// The pixel format. + /// The . + /// The source rectangle + /// The transformation matrix. + /// The size of the result image. + /// The to perform the resampling. + /// The + public static IImageProcessingContext Transform( + this IImageProcessingContext ctx, + Rectangle sourceRectangle, + Matrix4x4 transform, + Size targetDimensions, + IResampler sampler) + where TPixel : struct, IPixel + { + return ctx.ApplyProcessor( + new ProjectiveTransformProcessor(transform, sampler, targetDimensions), + sourceRectangle); + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs index e025851684..bdc66641a1 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs @@ -1,28 +1,31 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; using SixLabors.ImageSharp.Processing; -using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.Primitives; -using Xunit; namespace SixLabors.ImageSharp.Tests.Processing.Transforms { public class AffineTransformBuilderTests : TransformBuilderTestBase { protected override void AppendTranslation(AffineTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); + protected override void AppendScale(AffineTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); + protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); + protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians, Vector2 center) => builder.AppendRotationRadians(radians, center); protected override void PrependTranslation(AffineTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); + protected override void PrependScale(AffineTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); + protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians); - protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians, Vector2 center) => - builder.PrependRotationRadians(radians, center); + + protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians, Vector2 origin) => + builder.PrependRotationRadians(radians, origin); protected override AffineTransformBuilder CreateBuilder(Rectangle rectangle) => new AffineTransformBuilder(); @@ -35,4 +38,4 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms return Vector2.Transform(sourcePoint, matrix); } } -} +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs index 01448ac596..287d7be491 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs @@ -1,60 +1,40 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; using SixLabors.ImageSharp.Processing; using SixLabors.Primitives; -using Xunit; namespace SixLabors.ImageSharp.Tests.Processing.Transforms { public class ProjectiveTransformBuilderTests : TransformBuilderTestBase { - [Fact] - public void ConstructorAssignsProperties() - { - var s = new Size(1, 1); - var builder = new ProjectiveTransformBuilder(new Rectangle(Point.Empty, s)); - Assert.Equal(s, builder.Size); - } - - [Fact] - public void ConstructorThrowsInvalid() - { - Assert.Throws(() => - { - var s = new Size(0, 1); - var builder = new ProjectiveTransformBuilder(new Rectangle(Point.Empty, s)); - }); - - Assert.Throws(() => - { - var s = new Size(1, 0); - var builder = new ProjectiveTransformBuilder(new Rectangle(Point.Empty, s)); - }); - } - - protected override ProjectiveTransformBuilder CreateBuilder(Rectangle rectangle) => new ProjectiveTransformBuilder(rectangle); + protected override ProjectiveTransformBuilder CreateBuilder(Rectangle rectangle) => new ProjectiveTransformBuilder(); protected override void AppendTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); + protected override void AppendScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); + protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); + protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 center) => builder.AppendRotationRadians(radians, center); protected override void PrependTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); + protected override void PrependScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); + protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians); - protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 center) => - builder.PrependRotationRadians(radians, center); + + protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 origin) => + builder.PrependRotationRadians(radians, origin); protected override Vector2 Execute( ProjectiveTransformBuilder builder, Rectangle rectangle, Vector2 sourcePoint) { - Matrix4x4 matrix = builder.BuildMatrix(); + Matrix4x4 matrix = builder.BuildMatrix(rectangle); return Vector2.Transform(sourcePoint, matrix); } } diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs index 9436b7828c..1da660d222 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms IResampler sampler = GetResampler(resamplerName); using (Image image = provider.GetImage()) { - ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder(image.Size()) + ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder() .AppendTaper(TaperSide.Right, TaperCorner.Both, .5F); image.Mutate(i => i.Transform(builder, sampler)); @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { using (Image image = provider.GetImage()) { - ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder(image.Size()) + ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder() .AppendTaper(taperSide, taperCorner, .5F); image.Mutate(i => i.Transform(builder)); @@ -113,7 +113,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms Matrix4x4 matrix = Matrix4x4.Identity; matrix.M13 = 0.01F; - ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder(image.Size()) + ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder() .AppendMatrix(matrix); image.Mutate(i => i.Transform(builder)); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs index dffa3c7ac6..720c87cedf 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs @@ -18,7 +18,6 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms new TheoryData { // scale, translate, source, expectedDest - { Vector2.One, Vector2.Zero, Vector2.Zero, Vector2.Zero }, { Vector2.One, Vector2.Zero, new Vector2(10, 20), new Vector2(10, 20) }, { Vector2.One, new Vector2(3, 1), new Vector2(10, 20), new Vector2(13, 21) }, @@ -44,7 +43,6 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms new TheoryData { // translate, scale, source, expectedDest - { Vector2.Zero, Vector2.One, Vector2.Zero, Vector2.Zero }, { Vector2.Zero, Vector2.One, new Vector2(10, 20), new Vector2(10, 20) }, { new Vector2(3, 1), new Vector2(2, 0.5f), new Vector2(10, 20), new Vector2(26, 10.5f) }, @@ -183,14 +181,20 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected abstract TBuilder CreateBuilder(Rectangle rectangle); protected abstract void AppendTranslation(TBuilder builder, PointF translate); + protected abstract void AppendScale(TBuilder builder, SizeF scale); + protected abstract void AppendRotationRadians(TBuilder builder, float radians); + protected abstract void AppendRotationRadians(TBuilder builder, float radians, Vector2 center); protected abstract void PrependTranslation(TBuilder builder, PointF translate); + protected abstract void PrependScale(TBuilder builder, SizeF scale); + protected abstract void PrependRotationRadians(TBuilder builder, float radians); - protected abstract void PrependRotationRadians(TBuilder b1, float v, Vector2 vector2); + + protected abstract void PrependRotationRadians(TBuilder builder, float radians, Vector2 origin); protected virtual void AppendRotationDegrees(TBuilder builder, float degrees) => this.AppendRotationRadians(builder, GeometryUtilities.DegreeToRadian(degrees)); @@ -199,7 +203,5 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms this.AppendRotationRadians(builder, GeometryUtilities.DegreeToRadian(degrees), center); protected abstract Vector2 Execute(TBuilder builder, Rectangle rectangle, Vector2 sourcePoint); - - private static float Sqrt(float a) => (float)Math.Sqrt(a); } } \ No newline at end of file From a1b74ea1cb3e1fecddcb7af74cb4c48a46734060 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 27 Nov 2018 10:15:52 +0000 Subject: [PATCH 359/381] Add large jpeg to 32bit skip --- tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 5977e59cf3..15f7f92a83 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -49,7 +49,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Issues.NoEoiProgressive517, TestImages.Jpeg.Issues.BadRstProgressive518, TestImages.Jpeg.Issues.InvalidEOI695, - TestImages.Jpeg.Issues.ExifResizeOutOfRange696 + TestImages.Jpeg.Issues.ExifResizeOutOfRange696, + TestImages.Jpeg.Issues.ExifGetString750Transform }; return !TestEnvironment.Is64BitProcess && largeImagesToSkipOn32Bit.Contains(provider.SourceFileOrDescription); From 964ebcc1c30e965ab66be49c99f1dfad5d47e2b9 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 27 Nov 2018 10:23:06 +0000 Subject: [PATCH 360/381] Remove unused variables --- .../Processors/Transforms/AffineTransformProcessor.cs | 4 +--- .../Processors/Transforms/ProjectiveTransformProcessor.cs | 6 ++---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index aabaa63cf9..5a3b5943b7 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -69,14 +69,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // Handle tranforms that result in output identical to the original. if (this.TransformMatrix.Equals(default) || this.TransformMatrix.Equals(Matrix3x2.Identity)) { - // The cloned will be blank here copy all the pixel data over + // The clone will be blank here copy all the pixel data over source.GetPixelSpan().CopyTo(destination.GetPixelSpan()); return; } - int height = this.TargetDimensions.Height; int width = this.TargetDimensions.Width; - var targetBounds = new Rectangle(Point.Empty, this.TargetDimensions); // Convert from screen to world space. diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index 273156e2eb..98d488a420 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -65,14 +65,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // Handle tranforms that result in output identical to the original. if (this.TransformMatrix.Equals(default) || this.TransformMatrix.Equals(Matrix4x4.Identity)) { - // The cloned will be blank here copy all the pixel data over + // The clone will be blank here copy all the pixel data over source.GetPixelSpan().CopyTo(destination.GetPixelSpan()); return; } - int height = this.TargetDimensions.Height; int width = this.TargetDimensions.Width; - var targetBounds = new Rectangle(Point.Empty, this.TargetDimensions); // Convert from screen to world space. @@ -129,7 +127,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { // 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); + var v3 = Vector3.Transform(new Vector3(x, y, 1F), matrix); Vector2 point = new Vector2(v3.X, v3.Y) / MathF.Max(v3.Z, Epsilon); kernel.Convolve(point, x, ref ySpanRef, ref xSpanRef, source.PixelBuffer, vectorSpan); From 35ff16d5a6cb4caf54df2eba7646dc4eabd393b3 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 27 Nov 2018 12:12:42 +0000 Subject: [PATCH 361/381] Add Rotate(degrees, origin) --- .../Processing/AffineTransformBuilder.cs | 22 ++++++++++-- .../Processing/ProjectiveTransformBuilder.cs | 34 ++++++++++++++----- .../Transforms/AffineTransformBuilderTests.cs | 7 ++-- .../ProjectiveTransformBuilderTests.cs | 7 ++-- .../Transforms/TransformBuilderTestBase.cs | 8 ++--- 5 files changed, 59 insertions(+), 19 deletions(-) diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index 29c37d7bf0..ef0b24f815 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -35,7 +35,16 @@ namespace SixLabors.ImageSharp.Processing => this.Prepend(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); /// - /// Prepends a centered rotation matrix using the given rotation in radians. + /// Prepends a rotation matrix using the given rotation in degrees at the given origin. + /// + /// The amount of rotation, in degrees. + /// The rotation origin point. + /// The . + public AffineTransformBuilder PrependRotationDegrees(float degrees, Vector2 origin) + => this.PrependRotationRadians(GeometryUtilities.DegreeToRadian(degrees), origin); + + /// + /// Prepends a rotation matrix using the given rotation in radians at the given origin. /// /// The amount of rotation, in radians. /// The rotation origin point. @@ -62,7 +71,16 @@ namespace SixLabors.ImageSharp.Processing => this.Append(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); /// - /// Appends a centered rotation matrix using the given rotation in radians. + /// Appends a rotation matrix using the given rotation in degrees at the given origin. + /// + /// The amount of rotation, in degrees. + /// The rotation origin point. + /// The . + public AffineTransformBuilder AppendRotationDegrees(float degrees, Vector2 origin) + => this.AppendRotationRadians(GeometryUtilities.DegreeToRadian(degrees), origin); + + /// + /// Appends a rotation matrix using the given rotation in radians at the given origin. /// /// The amount of rotation, in radians. /// The rotation origin point. diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index a905467bba..5a19b890d9 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -53,13 +53,22 @@ namespace SixLabors.ImageSharp.Processing => this.Prepend(size => new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, size))); /// - /// Appends a centered rotation matrix using the given rotation in radians. + /// Prepends a centered rotation matrix using the given rotation in degrees at the given origin. + /// + /// The amount of rotation, in radians. + /// The rotation origin point. + /// The . + internal ProjectiveTransformBuilder PrependRotationDegrees(float degrees, Vector2 origin) + => this.PrependRotationRadians(GeometryUtilities.DegreeToRadian(degrees), origin); + + /// + /// Prepends a centered rotation matrix using the given rotation in radians at the given origin. /// /// The amount of rotation, in radians. - /// The rotation center. + /// The rotation origin point. /// The . - internal ProjectiveTransformBuilder PrependRotationRadians(float radians, Vector2 centerPoint) - => this.PrependMatrix(Matrix4x4.CreateRotationZ(radians, new Vector3(centerPoint, 0))); + internal ProjectiveTransformBuilder PrependRotationRadians(float radians, Vector2 origin) + => this.PrependMatrix(Matrix4x4.CreateRotationZ(radians, new Vector3(origin, 0))); /// /// Appends a centered rotation matrix using the given rotation in degrees. @@ -78,13 +87,22 @@ namespace SixLabors.ImageSharp.Processing => this.Append(size => new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, size))); /// - /// Appends a centered rotation matrix using the given rotation in radians. + /// Appends a centered rotation matrix using the given rotation in degrees at the given origin. + /// + /// The amount of rotation, in radians. + /// The rotation origin point. + /// The . + internal ProjectiveTransformBuilder AppendRotationDegrees(float degrees, Vector2 origin) + => this.AppendRotationRadians(GeometryUtilities.DegreeToRadian(degrees), origin); + + /// + /// Appends a centered rotation matrix using the given rotation in radians at the given origin. /// /// The amount of rotation, in radians. - /// The rotation center. + /// The rotation origin point. /// The . - internal ProjectiveTransformBuilder AppendRotationRadians(float radians, Vector2 centerPoint) - => this.AppendMatrix(Matrix4x4.CreateRotationZ(radians, new Vector3(centerPoint, 0))); + internal ProjectiveTransformBuilder AppendRotationRadians(float radians, Vector2 origin) + => this.AppendMatrix(Matrix4x4.CreateRotationZ(radians, new Vector3(origin, 0))); /// /// Prepends a scale matrix from the given uniform scale. diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs index bdc66641a1..14b8672641 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs @@ -15,8 +15,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); - protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians, Vector2 center) => - builder.AppendRotationRadians(radians, center); + protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians, Vector2 origin) => builder.AppendRotationRadians(radians, origin); + + protected override void AppendRotationDegrees(AffineTransformBuilder builder, float degrees) => builder.AppendRotationDegrees(degrees); + + protected override void AppendRotationDegrees(AffineTransformBuilder builder, float degrees, Vector2 origin) => builder.AppendRotationDegrees(degrees, origin); protected override void PrependTranslation(AffineTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs index 287d7be491..9f58826cd8 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs @@ -17,8 +17,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); - protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 center) => - builder.AppendRotationRadians(radians, center); + protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 origin) => builder.AppendRotationRadians(radians, origin); + + protected override void AppendRotationDegrees(ProjectiveTransformBuilder builder, float degrees) => builder.AppendRotationDegrees(degrees); + + protected override void AppendRotationDegrees(ProjectiveTransformBuilder builder, float degrees, Vector2 origin) => builder.AppendRotationDegrees(degrees, origin); protected override void PrependTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs index 720c87cedf..43ad756e04 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs @@ -186,7 +186,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected abstract void AppendRotationRadians(TBuilder builder, float radians); - protected abstract void AppendRotationRadians(TBuilder builder, float radians, Vector2 center); + protected abstract void AppendRotationRadians(TBuilder builder, float radians, Vector2 origin); protected abstract void PrependTranslation(TBuilder builder, PointF translate); @@ -196,11 +196,9 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected abstract void PrependRotationRadians(TBuilder builder, float radians, Vector2 origin); - protected virtual void AppendRotationDegrees(TBuilder builder, float degrees) => - this.AppendRotationRadians(builder, GeometryUtilities.DegreeToRadian(degrees)); + protected abstract void AppendRotationDegrees(TBuilder builder, float degrees); - protected virtual void AppendRotationDegrees(TBuilder builder, float degrees, Vector2 center) => - this.AppendRotationRadians(builder, GeometryUtilities.DegreeToRadian(degrees), center); + protected abstract void AppendRotationDegrees(TBuilder builder, float degrees, Vector2 origin); protected abstract Vector2 Execute(TBuilder builder, Rectangle rectangle, Vector2 sourcePoint); } From 65ce05d8c961358b4ca1543c901804ccb4a9c7cd Mon Sep 17 00:00:00 2001 From: Anton Firsov Date: Tue, 27 Nov 2018 21:37:57 +0100 Subject: [PATCH 362/381] Update CONTRIBUTING.md --- .github/CONTRIBUTING.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 188c11ff31..19941e65ee 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -20,6 +20,11 @@ * Do not open an issue on GitHub until you have collected positive feedback about the change. GitHub issues are primarily intended for bug reports and fixes. +#### **Running tests and Debugging** + +* Expected test output is pulled in as a submodule from the [ImageSharp.Tests.Images repository](https://github.com/SixLabors/Imagesharp.Tests.Images/tree/master/ReferenceOutput). To succesfully run tests, make sure that you have updated the submodules! +* Debugging (running tests in Debug mode) is only supported on .NET Core 2.1, because of JIT Code Generation bugs like dotnet/coreclr#16443 or dotnet/coreclr#20657 + #### **Do you have questions about consuming the library or the source code?** * Ask any question about how to use ImageSharp in the [ImageSharp Gitter Chat Room](https://gitter.im/ImageSharp/General). From 836738c5b5e1edf2dab63753e82ea0050e32f931 Mon Sep 17 00:00:00 2001 From: Anton Firsov Date: Tue, 27 Nov 2018 21:41:01 +0100 Subject: [PATCH 363/381] Fix links --- .github/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 19941e65ee..01c09d2231 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -23,7 +23,7 @@ #### **Running tests and Debugging** * Expected test output is pulled in as a submodule from the [ImageSharp.Tests.Images repository](https://github.com/SixLabors/Imagesharp.Tests.Images/tree/master/ReferenceOutput). To succesfully run tests, make sure that you have updated the submodules! -* Debugging (running tests in Debug mode) is only supported on .NET Core 2.1, because of JIT Code Generation bugs like dotnet/coreclr#16443 or dotnet/coreclr#20657 +* Debugging (running tests in Debug mode) is only supported on .NET Core 2.1, because of JIT Code Generation bugs like [dotnet/coreclr#16443](https://github.com/dotnet/coreclr/issues/16443) or [dotnet/coreclr#20657](https://github.com/dotnet/coreclr/issues/20657) #### **Do you have questions about consuming the library or the source code?** From 70206614fc55bc20d8512af821450aa090f82137 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 27 Nov 2018 20:44:35 +0100 Subject: [PATCH 364/381] refactor KernelMap initialization --- .../Processors/Transforms/KernelMap.cs | 94 +++++++++++-------- .../KernelMapTests.ReferenceKernelMap.cs | 4 +- .../Processors/Transforms/KernelMapTests.cs | 18 +++- .../Processors/Transforms/ResizeTests.cs | 31 +++++- 4 files changed, 102 insertions(+), 45 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs index 3f2bf8dda4..96eb976495 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs @@ -15,28 +15,38 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// internal class KernelMap : IDisposable { - private readonly Buffer2D data; + private readonly IResampler sampler; - private readonly ResizeKernel[] kernels; + private readonly int sourceSize; + + private readonly float ratio; - private int period; + private readonly float scale; - private int radius; + private readonly int radius; - private int periodicRegionMin; + private readonly Buffer2D data; - private int periodicRegionMax; + private readonly ResizeKernel[] kernels; - private KernelMap(MemoryAllocator memoryAllocator, int destinationSize, int radius, int period) + private KernelMap( + MemoryAllocator memoryAllocator, + IResampler sampler, + int sourceSize, + int destinationSize, + int bufferHeight, + float ratio, + float scale, + int radius) { - this.DestinationSize = destinationSize; - this.period = period; + this.sampler = sampler; + this.ratio = ratio; + this.scale = scale; this.radius = radius; - this.periodicRegionMin = period + radius; - this.periodicRegionMax = destinationSize - radius; - - int width = (radius * 2) + 1; - this.data = memoryAllocator.Allocate2D(width, destinationSize, AllocationOptions.Clean); + this.sourceSize = sourceSize; + this.DestinationSize = destinationSize; + int maxWidth = (radius * 2) + 1; + this.data = memoryAllocator.Allocate2D(maxWidth, bufferHeight, AllocationOptions.Clean); this.kernels = new ResizeKernel[destinationSize]; } @@ -79,61 +89,69 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize; - int radius = (int)MathF.Ceiling(scale * sampler.Radius); - var result = new KernelMap(memoryAllocator, destinationSize, radius, period); - for (int i = 0; i < destinationSize; i++) + var result = new KernelMap( + memoryAllocator, + sampler, + sourceSize, + destinationSize, + destinationSize, + ratio, + scale, + radius); + + result.BasicInit(); + + return result; + } + + private void BasicInit() + { + for (int i = 0; i < this.DestinationSize; i++) { - float center = ((i + .5F) * ratio) - .5F; + float center = ((i + .5F) * this.ratio) - .5F; // Keep inside bounds. - int left = (int)MathF.Ceiling(center - radius); + int left = (int)MathF.Ceiling(center - this.radius); if (left < 0) { left = 0; } - int right = (int)MathF.Floor(center + radius); - if (right > sourceSize - 1) + int right = (int)MathF.Floor(center + this.radius); + if (right > this.sourceSize - 1) { - right = sourceSize - 1; + right = this.sourceSize - 1; } float sum = 0; - ResizeKernel ws = result.CreateKernel(i, left, right); - result.kernels[i] = ws; + ResizeKernel kernel = this.CreateKernel(i, left, right); + this.kernels[i] = kernel; - ref float weightsBaseRef = ref MemoryMarshal.GetReference(ws.GetValues()); + ref float kernelBaseRef = ref MemoryMarshal.GetReference(kernel.GetValues()); for (int j = left; j <= right; j++) { - float weight = sampler.GetValue((j - center) / scale); - sum += weight; + float value = this.sampler.GetValue((j - center) / this.scale); + sum += value; // weights[j - left] = weight: - Unsafe.Add(ref weightsBaseRef, j - left) = weight; + Unsafe.Add(ref kernelBaseRef, j - left) = value; } // 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++) + for (int w = 0; w < kernel.Length; w++) { // weights[w] = weights[w] / sum: - ref float wRef = ref Unsafe.Add(ref weightsBaseRef, w); - wRef /= sum; + ref float kRef = ref Unsafe.Add(ref kernelBaseRef, w); + kRef /= sum; } } } - - return result; - } - - private int ReduceIndex(int destIndex) - { - return destIndex; } /// diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs index cf0e94e8b4..3786ec6e38 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms public ReferenceKernel GetKernel(int destinationIndex) => this.kernels[destinationIndex]; - public static ReferenceKernelMap Calculate(IResampler sampler, int destinationSize, int sourceSize) + public static ReferenceKernelMap Calculate(IResampler sampler, int destinationSize, int sourceSize, bool normalize = true) { float ratio = (float)sourceSize / destinationSize; float scale = ratio; @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms result.Add(new ReferenceKernel(left, values)); - if (sum > 0) + if (sum > 0 && normalize) { for (int w = 0; w < values.Length; w++) { diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index c5916ce0be..69de5dbbf2 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -35,6 +35,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { nameof(KnownResamplers.Bicubic), 500, 200 }, { nameof(KnownResamplers.Bicubic), 200, 500 }, + { nameof(KnownResamplers.Bicubic), 10, 25 }, + { nameof(KnownResamplers.Lanczos3), 16, 12 }, { nameof(KnownResamplers.Lanczos3), 12, 16 }, { nameof(KnownResamplers.Lanczos3), 12, 9 }, @@ -43,12 +45,26 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { nameof(KnownResamplers.Lanczos3), 8, 6 }, { nameof(KnownResamplers.Lanczos3), 20, 12 }, + { nameof(KnownResamplers.Lanczos3), 5, 25 }, + { nameof(KnownResamplers.Lanczos3), 5, 50 }, + { nameof(KnownResamplers.Lanczos8), 500, 200 }, { nameof(KnownResamplers.Lanczos8), 100, 10 }, { nameof(KnownResamplers.Lanczos8), 100, 80 }, { nameof(KnownResamplers.Lanczos8), 10, 100 }, }; + [Theory] + [MemberData(nameof(KernelMapData))] + public void PrintNonNormalizedKernelMap(string resamplerName, int srcSize, int destSize) + { + IResampler resampler = TestUtils.GetResampler(resamplerName); + + var kernelMap = ReferenceKernelMap.Calculate(resampler, destSize, srcSize, false); + + this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); + } + [Theory] [MemberData(nameof(KernelMapData))] public void KernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) @@ -60,7 +76,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms #if DEBUG this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); - this.Output.WriteLine($"Reference KernelMap:\n{PrintKernelMap(referenceMap)}\n"); + // this.Output.WriteLine($"Reference KernelMap:\n{PrintKernelMap(referenceMap)}\n"); #endif for (int i = 0; i < kernelMap.DestinationSize; i++) diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index bec64e4d37..42cb083f13 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; +// ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { @@ -20,7 +21,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.07F); - public static readonly TheoryData AllReSamplers = + public static readonly TheoryData AllResamplers = new TheoryData { { "Bicubic", KnownResamplers.Bicubic }, @@ -40,9 +41,9 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms }; [Theory] - [WithTestPatternImages(nameof(AllReSamplers), 100, 100, DefaultPixelType, 0.5f)] - [WithFileCollection(nameof(CommonTestImages), nameof(AllReSamplers), DefaultPixelType, 0.5f)] - [WithFileCollection(nameof(CommonTestImages), nameof(AllReSamplers), DefaultPixelType, 0.3f)] + [WithTestPatternImages(nameof(AllResamplers), 100, 100, DefaultPixelType, 0.5f)] + [WithFileCollection(nameof(CommonTestImages), nameof(AllResamplers), DefaultPixelType, 0.5f)] + [WithFileCollection(nameof(CommonTestImages), nameof(AllResamplers), DefaultPixelType, 0.3f)] public void Resize_WorksWithAllResamplers(TestImageProvider provider, string name, IResampler sampler, float ratio) where TPixel : struct, IPixel { @@ -57,6 +58,28 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } } + [Theory] + [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.Bicubic), 1)] + [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.Bicubic), 10)] + [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.Lanczos3), 10)] + [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.Lanczos8), 10)] + [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.NearestNeighbor), 10)] + [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32, nameof(KnownResamplers.NearestNeighbor), 1)] + [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32, nameof(KnownResamplers.NearestNeighbor), 5)] + [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32, nameof(KnownResamplers.Bicubic), 5)] + public void ScaleUp(TestImageProvider provider, string samplerName, float ratio) + where TPixel : struct, IPixel + { + using (Image image = provider.GetImage()) + { + SizeF newSize = image.Size() * ratio; + image.Mutate(x => x.Resize((Size)newSize, TestUtils.GetResampler(samplerName), false)); + FormattableString details = $"{samplerName}_{ratio.ToString(System.Globalization.CultureInfo.InvariantCulture)}"; + + image.DebugSave(provider, details); + } + } + [Theory] [WithFileCollection(nameof(CommonTestImages), DefaultPixelType, 1)] [WithFileCollection(nameof(CommonTestImages), DefaultPixelType, 4)] From e2ff889f45fbd56d8995ed516fab3388a59b9685 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 28 Nov 2018 00:51:15 +0100 Subject: [PATCH 365/381] rename KernelMap to ResizeKernelMap, introduce MosaicKernelMap, move source code --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 3 +- src/ImageSharp/ImageSharp.csproj.DotSettings | 4 +- .../{ => Resamplers}/BicubicResampler.cs | 0 .../{ => Resamplers}/BoxResampler.cs | 0 .../{ => Resamplers}/CatmullRomResampler.cs | 0 .../{ => Resamplers}/HermiteResampler.cs | 0 .../{ => Resamplers}/Lanczos2Resampler.cs | 0 .../{ => Resamplers}/Lanczos3Resampler.cs | 0 .../{ => Resamplers}/Lanczos5Resampler.cs | 0 .../{ => Resamplers}/Lanczos8Resampler.cs | 0 .../MitchellNetravaliResampler.cs | 0 .../NearestNeighborResampler.cs | 0 .../{ => Resamplers}/RobidouxResampler.cs | 0 .../RobidouxSharpResampler.cs | 0 .../{ => Resamplers}/SplineResampler.cs | 0 .../{ => Resamplers}/TriangleResampler.cs | 0 .../{ => Resamplers}/WelchResampler.cs | 0 .../Transforms/{ => Resize}/ResizeKernel.cs | 22 +++--- .../Resize/ResizeKernelMap.MosaicKernelMap.cs | 46 ++++++++++++ .../ResizeKernelMap.cs} | 70 ++++++++++++------- .../{ => Resize}/ResizeProcessor.cs | 8 +-- .../KernelMapTests.ReferenceKernelMap.cs | 2 +- .../Processors/Transforms/KernelMapTests.cs | 4 +- .../Processors/Transforms/ResizeTests.cs | 1 + 24 files changed, 115 insertions(+), 45 deletions(-) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/BicubicResampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/BoxResampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/CatmullRomResampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/HermiteResampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/Lanczos2Resampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/Lanczos3Resampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/Lanczos5Resampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/Lanczos8Resampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/MitchellNetravaliResampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/NearestNeighborResampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/RobidouxResampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/RobidouxSharpResampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/SplineResampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/TriangleResampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/WelchResampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resize}/ResizeKernel.cs (81%) create mode 100644 src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs rename src/ImageSharp/Processing/Processors/Transforms/{KernelMap.cs => Resize/ResizeKernelMap.cs} (69%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resize}/ResizeProcessor.cs (98%) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index f07ccb03b4..45cb52fd95 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -5,6 +5,7 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.Primitives; namespace SixLabors.ImageSharp @@ -98,7 +99,7 @@ namespace SixLabors.ImageSharp /// /// Determine the Least Common Multiple (LCM) of two numbers. - /// TODO: This method might be useful for building a more compact + /// TODO: This method might be useful for building a more compact /// public static int LeastCommonMultiple(int a, int b) { diff --git a/src/ImageSharp/ImageSharp.csproj.DotSettings b/src/ImageSharp/ImageSharp.csproj.DotSettings index cd75f91b7b..a7337240a5 100644 --- a/src/ImageSharp/ImageSharp.csproj.DotSettings +++ b/src/ImageSharp/ImageSharp.csproj.DotSettings @@ -5,4 +5,6 @@ True True True - True \ No newline at end of file + True + True + True \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/BicubicResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/BicubicResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/BicubicResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/BicubicResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/BoxResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/BoxResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/BoxResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/BoxResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/CatmullRomResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/CatmullRomResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/CatmullRomResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/CatmullRomResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/HermiteResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/HermiteResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/HermiteResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/HermiteResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/Lanczos2Resampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos2Resampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/Lanczos2Resampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos2Resampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/Lanczos3Resampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos3Resampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/Lanczos3Resampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos3Resampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/Lanczos5Resampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos5Resampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/Lanczos5Resampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos5Resampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/Lanczos8Resampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos8Resampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/Lanczos8Resampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos8Resampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/MitchellNetravaliResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/MitchellNetravaliResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/MitchellNetravaliResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/MitchellNetravaliResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/NearestNeighborResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/NearestNeighborResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/NearestNeighborResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/NearestNeighborResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/RobidouxResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/RobidouxResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/RobidouxResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/RobidouxResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/RobidouxSharpResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/RobidouxSharpResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/RobidouxSharpResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/RobidouxSharpResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/SplineResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/SplineResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/SplineResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/SplineResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/TriangleResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/TriangleResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/TriangleResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/TriangleResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/WelchResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/WelchResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/WelchResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/WelchResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs similarity index 81% rename from src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs index 1ce9c9c91e..1183de7541 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs @@ -11,18 +11,21 @@ using SixLabors.ImageSharp.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 ResizeKernel + internal unsafe struct ResizeKernel { + private readonly float* bufferPtr; + /// /// Initializes a new instance of the struct. /// [MethodImpl(InliningOptions.ShortMethod)] - internal ResizeKernel(int left, Memory bufferSlice) + internal ResizeKernel(int left, float* bufferPtr, int length) { this.Left = left; - this.BufferSlice = bufferSlice; + this.bufferPtr = bufferPtr; + this.Length = length; } /// @@ -30,22 +33,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// public int Left { get; } - /// - /// Gets the slice of the buffer containing the weights values. - /// - public Memory BufferSlice { get; } - /// /// Gets the the length of the kernel /// - public int Length => this.BufferSlice.Length; + public int Length { get; } /// - /// 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(InliningOptions.ShortMethod)] - public Span GetValues() => this.BufferSlice.Span; + public Span GetValues() => new Span(this.bufferPtr, this.Length); /// /// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this instance. diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs new file mode 100644 index 0000000000..b815d05cbc --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs @@ -0,0 +1,46 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +using SixLabors.Memory; + +namespace SixLabors.ImageSharp.Processing.Processors.Transforms +{ + /// + /// Contains + /// + internal partial class ResizeKernelMap + { + /// + /// Memory-optimized where repeating rows are stored only once. + /// + private sealed class MosaicKernelMap : ResizeKernelMap + { + private readonly int period; + + private readonly int cornerInterval; + + public MosaicKernelMap( + MemoryAllocator memoryAllocator, + IResampler sampler, + int sourceSize, + int destinationSize, + float ratio, + float scale, + int radius, + int period, + int cornerInterval) + : base( + memoryAllocator, + sampler, + sourceSize, + destinationSize, + (cornerInterval * 2) + period, + ratio, + scale, + radius) + { + this.cornerInterval = cornerInterval; + this.period = period; + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs similarity index 69% rename from src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index 96eb976495..443db72d9e 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -11,9 +12,10 @@ using SixLabors.Memory; namespace SixLabors.ImageSharp.Processing.Processors.Transforms { /// - /// Holds the values in an optimized contigous memory region. + /// Provides values from an optimized, + /// contigous memory region. /// - internal class KernelMap : IDisposable + internal partial class ResizeKernelMap : IDisposable { private readonly IResampler sampler; @@ -25,11 +27,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private readonly int radius; + private readonly MemoryHandle pinHandle; + private readonly Buffer2D data; private readonly ResizeKernel[] kernels; - private KernelMap( + private ResizeKernelMap( MemoryAllocator memoryAllocator, IResampler sampler, int sourceSize, @@ -47,16 +51,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.DestinationSize = destinationSize; int maxWidth = (radius * 2) + 1; this.data = memoryAllocator.Allocate2D(maxWidth, bufferHeight, AllocationOptions.Clean); + this.pinHandle = this.data.Memory.Pin(); this.kernels = new ResizeKernel[destinationSize]; } public int DestinationSize { get; } /// - /// Disposes instance releasing it's backing buffer. + /// Disposes instance releasing it's backing buffer. /// public void Dispose() { + this.pinHandle.Dispose(); this.data.Dispose(); } @@ -73,8 +79,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The destination size /// The source size /// The to use for buffer allocations - /// The - public static KernelMap Calculate( + /// The + public static ResizeKernelMap Calculate( IResampler sampler, int destinationSize, int sourceSize, @@ -88,25 +94,40 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms scale = 1F; } - int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize; int radius = (int)MathF.Ceiling(scale * sampler.Radius); - - var result = new KernelMap( - memoryAllocator, - sampler, - sourceSize, - destinationSize, - destinationSize, - ratio, - scale, - radius); - - result.BasicInit(); + int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize; + float center0 = (ratio - 1) * 0.5f; + int cornerInterval = (int)MathF.Ceiling((radius - center0 - 1) / ratio); + + bool useMosaic = 2 * (cornerInterval + period) < destinationSize; + + ResizeKernelMap result = useMosaic + ? new ResizeKernelMap( + memoryAllocator, + sampler, + sourceSize, + destinationSize, + destinationSize, + ratio, + scale, + radius) + : new MosaicKernelMap( + memoryAllocator, + sampler, + sourceSize, + destinationSize, + ratio, + scale, + radius, + period, + cornerInterval); + + result.Init(); return result; } - private void BasicInit() + protected virtual void Init() { for (int i = 0; i < this.DestinationSize; i++) { @@ -157,7 +178,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// Slices a weights value at the given positions. /// - private ResizeKernel CreateKernel(int destIdx, int left, int rightIdx) + private unsafe ResizeKernel CreateKernel(int destIdx, int left, int rightIdx) { int length = rightIdx - left + 1; @@ -166,10 +187,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms throw new InvalidOperationException($"Error in KernelMap.CreateKernel({destIdx},{left},{rightIdx}): left > this.data.Width"); } - int flatStartIndex = destIdx * this.data.Width; + Span rowSpan = this.data.GetRowSpan(destIdx); - Memory bufferSlice = this.data.Memory.Slice(flatStartIndex, length); - return new ResizeKernel(left, bufferSlice); + ref float rowReference = ref MemoryMarshal.GetReference(rowSpan); + float* rowPtr = (float*)Unsafe.AsPointer(ref rowReference); + return new ResizeKernel(left, rowPtr, length); } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs similarity index 98% rename from src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs index 7c9d39fc55..189e21de7a 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/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 KernelMap horizontalKernelMap; - private KernelMap verticalKernelMap; + private ResizeKernelMap horizontalKernelMap; + private ResizeKernelMap verticalKernelMap; /// /// Initializes a new instance of the class. @@ -165,13 +165,13 @@ 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.horizontalKernelMap = KernelMap.Calculate( + this.horizontalKernelMap = ResizeKernelMap.Calculate( this.Sampler, this.ResizeRectangle.Width, sourceRectangle.Width, memoryAllocator); - this.verticalKernelMap = KernelMap.Calculate( + this.verticalKernelMap = ResizeKernelMap.Calculate( this.Sampler, this.ResizeRectangle.Height, sourceRectangle.Height, diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs index 3786ec6e38..85a930fb9a 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms public partial class KernelMapTests { /// - /// Simplified reference implementation for functionality. + /// Simplified reference implementation for functionality. /// internal class ReferenceKernelMap { diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index 69de5dbbf2..4d005576c2 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms IResampler resampler = TestUtils.GetResampler(resamplerName); var referenceMap = ReferenceKernelMap.Calculate(resampler, destSize, srcSize); - var kernelMap = KernelMap.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator); + var kernelMap = ResizeKernelMap.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator); #if DEBUG this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); @@ -103,7 +103,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } } - private static string PrintKernelMap(KernelMap kernelMap) => + private static string PrintKernelMap(ResizeKernelMap kernelMap) => PrintKernelMap(kernelMap, km => km.DestinationSize, (km, i) => km.GetKernel(i)); private static string PrintKernelMap(ReferenceKernelMap kernelMap) => diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index 42cb083f13..839d26e71c 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs @@ -58,6 +58,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } } + // TODO: Merge with the previous theory + add test images [Theory] [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.Bicubic), 1)] [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.Bicubic), 10)] From e2279a04aa1e5c806b79f31c02bf27b4f83647f1 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 28 Nov 2018 01:12:17 +0100 Subject: [PATCH 366/381] preparations for implementing MosaicKernelMap --- .../Transforms/Resize/ResizeKernel.cs | 12 +- .../Resize/ResizeKernelMap.MosaicKernelMap.cs | 5 + .../Transforms/Resize/ResizeKernelMap.cs | 131 ++++++++++-------- .../KernelMapTests.ReferenceKernelMap.cs | 2 +- .../Processors/Transforms/KernelMapTests.cs | 2 +- 5 files changed, 86 insertions(+), 66 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs index 1183de7541..b2d7d21167 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs @@ -41,9 +41,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// Gets the span representing the portion of the that this window covers /// - /// The - [MethodImpl(InliningOptions.ShortMethod)] - public Span GetValues() => new Span(this.bufferPtr, this.Length); + /// The + /// + public Span Values + { + [MethodImpl(InliningOptions.ShortMethod)] + get => new Span(this.bufferPtr, this.Length); + } /// /// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this instance. @@ -53,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms [MethodImpl(InliningOptions.ShortMethod)] public Vector4 Convolve(Span rowSpan) { - ref float horizontalValues = ref MemoryMarshal.GetReference(this.GetValues()); + ref float horizontalValues = ref Unsafe.AsRef(this.bufferPtr); int left = this.Left; ref Vector4 vecPtr = ref Unsafe.Add(ref MemoryMarshal.GetReference(rowSpan), left); diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs index b815d05cbc..09ae796777 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs @@ -41,6 +41,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.cornerInterval = cornerInterval; this.period = period; } + + protected override void Initialize() + { + base.Initialize(); + } } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index 443db72d9e..ebb15d3768 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } /// - /// Returns a for an index value between 0 and destinationSize - 1. + /// Returns a for an index value between 0 and DestinationSize - 1. /// [MethodImpl(InliningOptions.ShortMethod)] public ref ResizeKernel GetKernel(int destIdx) => ref this.kernels[destIdx]; @@ -101,93 +101,104 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms bool useMosaic = 2 * (cornerInterval + period) < destinationSize; + useMosaic = false; + ResizeKernelMap result = useMosaic - ? new ResizeKernelMap( - memoryAllocator, - sampler, - sourceSize, - destinationSize, - destinationSize, - ratio, - scale, - radius) - : new MosaicKernelMap( - memoryAllocator, - sampler, - sourceSize, - destinationSize, - ratio, - scale, - radius, - period, - cornerInterval); - - result.Init(); + ? new MosaicKernelMap( + memoryAllocator, + sampler, + sourceSize, + destinationSize, + ratio, + scale, + radius, + period, + cornerInterval) + : new ResizeKernelMap( + memoryAllocator, + sampler, + sourceSize, + destinationSize, + destinationSize, + ratio, + scale, + radius); + + result.Initialize(); return result; } - protected virtual void Init() + protected virtual void Initialize() { - for (int i = 0; i < this.DestinationSize; i++) + for (int destRowIndex = 0; destRowIndex < this.DestinationSize; destRowIndex++) { - float center = ((i + .5F) * this.ratio) - .5F; + ResizeKernel kernel = this.BuildKernelRow(destRowIndex, destRowIndex); + this.kernels[destRowIndex] = kernel; + } + } - // Keep inside bounds. - int left = (int)MathF.Ceiling(center - this.radius); - if (left < 0) - { - left = 0; - } + private ResizeKernel BuildKernelRow(int destRowIndex, int dataRowIndex) + { + float center = ((destRowIndex + .5F) * this.ratio) - .5F; - int right = (int)MathF.Floor(center + this.radius); - if (right > this.sourceSize - 1) - { - right = this.sourceSize - 1; - } + // Keep inside bounds. + int left = (int)MathF.Ceiling(center - this.radius); + if (left < 0) + { + left = 0; + } - float sum = 0; + int right = (int)MathF.Floor(center + this.radius); + if (right > this.sourceSize - 1) + { + right = this.sourceSize - 1; + } - ResizeKernel kernel = this.CreateKernel(i, left, right); - this.kernels[i] = kernel; + float sum = 0; - ref float kernelBaseRef = ref MemoryMarshal.GetReference(kernel.GetValues()); + ResizeKernel kernel = this.GetKernel(dataRowIndex, left, right); - for (int j = left; j <= right; j++) - { - float value = this.sampler.GetValue((j - center) / this.scale); - sum += value; + ref float kernelBaseRef = ref MemoryMarshal.GetReference(kernel.Values); - // weights[j - left] = weight: - Unsafe.Add(ref kernelBaseRef, j - left) = value; - } + for (int j = left; j <= right; j++) + { + float value = this.sampler.GetValue((j - center) / this.scale); + sum += value; - // Normalize, best to do it here rather than in the pixel loop later on. - if (sum > 0) + // weights[j - left] = weight: + Unsafe.Add(ref kernelBaseRef, j - left) = value; + } + + // Normalize, best to do it here rather than in the pixel loop later on. + if (sum > 0) + { + for (int w = 0; w < kernel.Length; w++) { - for (int w = 0; w < kernel.Length; w++) - { - // weights[w] = weights[w] / sum: - ref float kRef = ref Unsafe.Add(ref kernelBaseRef, w); - kRef /= sum; - } + // weights[w] = weights[w] / sum: + ref float kRef = ref Unsafe.Add(ref kernelBaseRef, w); + kRef /= sum; } } + + return kernel; } /// - /// Slices a weights value at the given positions. + /// Returns a referencing values of + /// at row . /// - private unsafe ResizeKernel CreateKernel(int destIdx, int left, int rightIdx) + private unsafe ResizeKernel GetKernel(int dataRowIndex, int left, int right) { - int length = rightIdx - left + 1; + int length = right - left + 1; if (length > this.data.Width) { - throw new InvalidOperationException($"Error in KernelMap.CreateKernel({destIdx},{left},{rightIdx}): left > this.data.Width"); + throw new InvalidOperationException( + $"Error in KernelMap.CreateKernel({dataRowIndex},{left},{right}): left > this.data.Width"); } - Span rowSpan = this.data.GetRowSpan(destIdx); + Span rowSpan = this.data.GetRowSpan(dataRowIndex); ref float rowReference = ref MemoryMarshal.GetReference(rowSpan); float* rowPtr = (float*)Unsafe.AsPointer(ref rowReference); diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs index 85a930fb9a..f7c3b27e5a 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs @@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms public static implicit operator ReferenceKernel(ResizeKernel orig) { - return new ReferenceKernel(orig.Left, orig.GetValues().ToArray()); + return new ReferenceKernel(orig.Left, orig.Values.ToArray()); } } } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index 4d005576c2..7b997e33f2 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms Assert.Equal(referenceKernel.Length, kernel.Length); Assert.Equal(referenceKernel.Left, kernel.Left); float[] expectedValues = referenceKernel.Values; - Span actualValues = kernel.GetValues(); + Span actualValues = kernel.Values; Assert.Equal(expectedValues.Length, actualValues.Length); From b33b5687d124ed1bf53368fa6f3403d4bbc6d7c8 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 28 Nov 2018 02:16:01 +0100 Subject: [PATCH 367/381] MosaicKernelMap works! --- .../Transforms/Resize/ResizeKernel.cs | 9 ++++-- .../Resize/ResizeKernelMap.MosaicKernelMap.cs | 32 ++++++++++++++++++- .../Transforms/Resize/ResizeKernelMap.cs | 26 +++++++++------ .../Processors/Transforms/KernelMapTests.cs | 16 ++++++++-- 4 files changed, 67 insertions(+), 16 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs index b2d7d21167..e10afce2e4 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs @@ -6,14 +6,12 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Memory; - namespace SixLabors.ImageSharp.Processing.Processors.Transforms { /// /// Points to a collection of of weights allocated in . /// - internal unsafe struct ResizeKernel + internal readonly unsafe struct ResizeKernel { private readonly float* bufferPtr; @@ -73,5 +71,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return result; } + + internal ResizeKernel AlterLeftValue(int left) + { + return new ResizeKernel(left, this.bufferPtr, this.Length); + } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs index 09ae796777..cf660a72f0 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs @@ -1,5 +1,8 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. + +using System; + using SixLabors.Memory; namespace SixLabors.ImageSharp.Processing.Processors.Transforms @@ -42,9 +45,36 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.period = period; } + internal override string Info => base.Info + $"|period:{this.period}|cornerInterval:{this.cornerInterval}"; + protected override void Initialize() { - base.Initialize(); + // Build top corner data + one period of the mosaic data: + int startOfFirstRepeatedMosaic = this.cornerInterval + this.period; + + for (int i = 0; i < startOfFirstRepeatedMosaic; i++) + { + ResizeKernel kernel = this.BuildKernel(i, i); + this.kernels[i] = kernel; + } + + // Copy the mosaics: + int bottomStartDest = this.DestinationSize - this.cornerInterval; + for (int i = startOfFirstRepeatedMosaic; i < bottomStartDest; i++) + { + float center = ((i + .5F) * this.ratio) - .5F; + int left = (int)MathF.Ceiling(center - this.radius); + ResizeKernel kernel = this.kernels[i - this.period]; + this.kernels[i] = kernel.AlterLeftValue(left); + } + + // Build bottom corner data: + int bottomStartData = this.cornerInterval + this.period; + for (int i = 0; i < this.cornerInterval; i++) + { + ResizeKernel kernel = this.BuildKernel(bottomStartDest + i, bottomStartData + i); + this.kernels[bottomStartDest + i] = kernel; + } } } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index ebb15d3768..262a39352c 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -57,6 +57,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public int DestinationSize { get; } + internal virtual string Info => + $"radius:{this.radius}|sourceSize:{this.sourceSize}|destinationSize:{this.DestinationSize}|ratio:{this.ratio}|scale:{this.scale}"; + /// /// Disposes instance releasing it's backing buffer. /// @@ -97,11 +100,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int radius = (int)MathF.Ceiling(scale * sampler.Radius); int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize; float center0 = (ratio - 1) * 0.5f; - int cornerInterval = (int)MathF.Ceiling((radius - center0 - 1) / ratio); + float firstNonNegativeLeftVal = (radius - center0 - 1) / ratio; + int cornerInterval = (int)MathF.Ceiling(firstNonNegativeLeftVal); - bool useMosaic = 2 * (cornerInterval + period) < destinationSize; + // corner case for cornerInteval: + if (firstNonNegativeLeftVal == cornerInterval) + { + cornerInterval++; + } - useMosaic = false; + bool useMosaic = 2 * (cornerInterval + period) < destinationSize; ResizeKernelMap result = useMosaic ? new MosaicKernelMap( @@ -131,14 +139,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms protected virtual void Initialize() { - for (int destRowIndex = 0; destRowIndex < this.DestinationSize; destRowIndex++) + for (int i = 0; i < this.DestinationSize; i++) { - ResizeKernel kernel = this.BuildKernelRow(destRowIndex, destRowIndex); - this.kernels[destRowIndex] = kernel; + ResizeKernel kernel = this.BuildKernel(i, i); + this.kernels[i] = kernel; } } - private ResizeKernel BuildKernelRow(int destRowIndex, int dataRowIndex) + private ResizeKernel BuildKernel(int destRowIndex, int dataRowIndex) { float center = ((destRowIndex + .5F) * this.ratio) - .5F; @@ -157,7 +165,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms float sum = 0; - ResizeKernel kernel = this.GetKernel(dataRowIndex, left, right); + ResizeKernel kernel = this.CreateKernel(dataRowIndex, left, right); ref float kernelBaseRef = ref MemoryMarshal.GetReference(kernel.Values); @@ -188,7 +196,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// Returns a referencing values of /// at row . /// - private unsafe ResizeKernel GetKernel(int dataRowIndex, int left, int right) + private unsafe ResizeKernel CreateKernel(int dataRowIndex, int left, int right) { int length = right - left + 1; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index 7b997e33f2..f0a0d738b9 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -48,6 +48,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { nameof(KnownResamplers.Lanczos3), 5, 25 }, { nameof(KnownResamplers.Lanczos3), 5, 50 }, + { nameof(KnownResamplers.Lanczos3), 25, 5 }, + { nameof(KnownResamplers.Lanczos3), 50, 5 }, + { nameof(KnownResamplers.Lanczos3), 49, 5 }, + { nameof(KnownResamplers.Lanczos3), 31, 5 }, + { nameof(KnownResamplers.Lanczos8), 500, 200 }, { nameof(KnownResamplers.Lanczos8), 100, 10 }, { nameof(KnownResamplers.Lanczos8), 100, 80 }, @@ -75,8 +80,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms var kernelMap = ResizeKernelMap.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator); #if DEBUG + this.Output.WriteLine($"Expected KernelMap:\n{PrintKernelMap(referenceMap)}\n"); this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); - // this.Output.WriteLine($"Reference KernelMap:\n{PrintKernelMap(referenceMap)}\n"); #endif for (int i = 0; i < kernelMap.DestinationSize; i++) @@ -92,7 +97,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms Assert.Equal(expectedValues.Length, actualValues.Length); - var comparer = new ApproximateFloatComparer(1e-6f); + var comparer = new ApproximateFloatComparer(1e-4f); for (int x = 0; x < expectedValues.Length; x++) { @@ -116,12 +121,17 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { var bld = new StringBuilder(); + if (kernelMap is ResizeKernelMap actualMap) + { + bld.AppendLine(actualMap.Info); + } + int destinationSize = getDestinationSize(kernelMap); for (int i = 0; i < destinationSize; i++) { ReferenceKernel kernel = getKernel(kernelMap, i); - bld.Append($"({kernel.Left:D3}) || "); + bld.Append($"[{i:D3}] (L{kernel.Left:D3}) || "); Span span = kernel.Values; for (int j = 0; j < kernel.Length; j++) From 2d96beed9acb84a061e96cf824274cb4356a240e Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 28 Nov 2018 02:24:35 +0100 Subject: [PATCH 368/381] format, docs, cleanup --- .../Transforms/Resize/ResizeKernel.cs | 4 ++ .../Resize/ResizeKernelMap.MosaicKernelMap.cs | 10 ++--- .../Transforms/Resize/ResizeKernelMap.cs | 37 ++++++++++++------- .../Processors/Transforms/KernelMapTests.cs | 4 +- 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs index e10afce2e4..04bf6c3a44 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs @@ -72,6 +72,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return result; } + /// + /// Copy the contents of altering + /// to the value . + /// internal ResizeKernel AlterLeftValue(int left) { return new ResizeKernel(left, this.bufferPtr, this.Length); diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs index cf660a72f0..e106b1ea0a 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs @@ -24,8 +24,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public MosaicKernelMap( MemoryAllocator memoryAllocator, IResampler sampler, - int sourceSize, - int destinationSize, + int sourceLength, + int destinationLength, float ratio, float scale, int radius, @@ -34,8 +34,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms : base( memoryAllocator, sampler, - sourceSize, - destinationSize, + sourceLength, + destinationLength, (cornerInterval * 2) + period, ratio, scale, @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } // Copy the mosaics: - int bottomStartDest = this.DestinationSize - this.cornerInterval; + int bottomStartDest = this.DestinationLength - this.cornerInterval; for (int i = startOfFirstRepeatedMosaic; i < bottomStartDest; i++) { float center = ((i + .5F) * this.ratio) - .5F; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index 262a39352c..ccb57114ae 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -13,13 +13,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { /// /// Provides values from an optimized, - /// contigous memory region. + /// contiguous memory region. /// internal partial class ResizeKernelMap : IDisposable { private readonly IResampler sampler; - private readonly int sourceSize; + private readonly int sourceLength; private readonly float ratio; @@ -36,8 +36,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private ResizeKernelMap( MemoryAllocator memoryAllocator, IResampler sampler, - int sourceSize, - int destinationSize, + int sourceLength, + int destinationLength, int bufferHeight, float ratio, float scale, @@ -47,18 +47,24 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.ratio = ratio; this.scale = scale; this.radius = radius; - this.sourceSize = sourceSize; - this.DestinationSize = destinationSize; + this.sourceLength = sourceLength; + this.DestinationLength = destinationLength; int maxWidth = (radius * 2) + 1; this.data = memoryAllocator.Allocate2D(maxWidth, bufferHeight, AllocationOptions.Clean); this.pinHandle = this.data.Memory.Pin(); - this.kernels = new ResizeKernel[destinationSize]; + this.kernels = new ResizeKernel[destinationLength]; } - public int DestinationSize { get; } + /// + /// Gets the length of the destination row/column + /// + public int DestinationLength { get; } + /// + /// Gets a string of information to help debugging + /// internal virtual string Info => - $"radius:{this.radius}|sourceSize:{this.sourceSize}|destinationSize:{this.DestinationSize}|ratio:{this.ratio}|scale:{this.scale}"; + $"radius:{this.radius}|sourceSize:{this.sourceLength}|destinationSize:{this.DestinationLength}|ratio:{this.ratio}|scale:{this.scale}"; /// /// Disposes instance releasing it's backing buffer. @@ -104,7 +110,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int cornerInterval = (int)MathF.Ceiling(firstNonNegativeLeftVal); // corner case for cornerInteval: - if (firstNonNegativeLeftVal == cornerInterval) + if (firstNonNegativeLeftVal == cornerInterval) { cornerInterval++; } @@ -139,13 +145,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms protected virtual void Initialize() { - for (int i = 0; i < this.DestinationSize; i++) + for (int i = 0; i < this.DestinationLength; i++) { ResizeKernel kernel = this.BuildKernel(i, i); this.kernels[i] = kernel; } } + /// + /// Builds a for the row (in ) + /// referencing the data at row within , + /// so the data reusable by other data rows. + /// private ResizeKernel BuildKernel(int destRowIndex, int dataRowIndex) { float center = ((destRowIndex + .5F) * this.ratio) - .5F; @@ -158,9 +169,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } int right = (int)MathF.Floor(center + this.radius); - if (right > this.sourceSize - 1) + if (right > this.sourceLength - 1) { - right = this.sourceSize - 1; + right = this.sourceLength - 1; } float sum = 0; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index f0a0d738b9..af98b99521 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); #endif - for (int i = 0; i < kernelMap.DestinationSize; i++) + for (int i = 0; i < kernelMap.DestinationLength; i++) { ResizeKernel kernel = kernelMap.GetKernel(i); @@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } private static string PrintKernelMap(ResizeKernelMap kernelMap) => - PrintKernelMap(kernelMap, km => km.DestinationSize, (km, i) => km.GetKernel(i)); + PrintKernelMap(kernelMap, km => km.DestinationLength, (km, i) => km.GetKernel(i)); private static string PrintKernelMap(ReferenceKernelMap kernelMap) => PrintKernelMap(kernelMap, km => km.DestinationSize, (km, i) => km.GetKernel(i)); From 8cdb72888db1200b5d8dc333989a8150dd38bb11 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 28 Nov 2018 14:21:53 +0000 Subject: [PATCH 369/381] Add Skew methods and tests. --- .../Processing/AffineTransformBuilder.cs | 58 ++++++++++++ .../Processors/Transforms/TransformUtils.cs | 12 +++ .../Processing/ProjectiveTransformBuilder.cs | 76 +++++++++++++++ .../Transforms/AffineTransformBuilderTests.cs | 51 +++++++--- .../ProjectiveTransformBuilderTests.cs | 30 ++++-- .../Transforms/TransformBuilderTestBase.cs | 94 ++++++++++++++++--- 6 files changed, 291 insertions(+), 30 deletions(-) diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index ef0b24f815..c3d01241c9 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -145,6 +145,35 @@ namespace SixLabors.ImageSharp.Processing public AffineTransformBuilder PrependSkewDegrees(float degreesX, float degreesY) => this.Prepend(size => TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, size)); + /// + /// Prepends a centered skew matrix from the give angles in radians. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The . + public AffineTransformBuilder PrependSkewRadians(float radiansX, float radiansY) + => this.Prepend(size => TransformUtils.CreateSkewMatrixRadians(radiansX, radiansY, size)); + + /// + /// Prepends a skew matrix using the given angles in degrees at the given origin. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The skew origin point. + /// The . + public AffineTransformBuilder PrependSkewDegrees(float degreesX, float degreesY, Vector2 origin) + => this.PrependSkewRadians(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY), origin); + + /// + /// Prepends a skew matrix using the given angles in radians at the given origin. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The skew origin point. + /// The . + public AffineTransformBuilder PrependSkewRadians(float radiansX, float radiansY, Vector2 origin) + => this.PrependMatrix(Matrix3x2.CreateSkew(radiansX, radiansY, origin)); + /// /// Appends a centered skew matrix from the give angles in degrees. /// @@ -154,6 +183,35 @@ namespace SixLabors.ImageSharp.Processing public AffineTransformBuilder AppendSkewDegrees(float degreesX, float degreesY) => this.Append(size => TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, size)); + /// + /// Appends a centered skew matrix from the give angles in radians. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The . + public AffineTransformBuilder AppendSkewRadians(float radiansX, float radiansY) + => this.Append(size => TransformUtils.CreateSkewMatrixRadians(radiansX, radiansY, size)); + + /// + /// Appends a skew matrix using the given angles in degrees at the given origin. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The skew origin point. + /// The . + public AffineTransformBuilder AppendSkewDegrees(float degreesX, float degreesY, Vector2 origin) + => this.AppendSkewRadians(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY), origin); + + /// + /// Appends a skew matrix using the given angles in radians at the given origin. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The skew origin point. + /// The . + public AffineTransformBuilder AppendSkewRadians(float radiansX, float radiansY, Vector2 origin) + => this.AppendMatrix(Matrix3x2.CreateSkew(radiansX, radiansY, origin)); + /// /// Prepends a translation matrix from the given vector. /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs index 6cef38f8fe..24b15d3098 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs @@ -46,6 +46,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms new Rectangle(Point.Empty, size), Matrix3x2Extensions.CreateSkewDegrees(degreesX, degreesY, PointF.Empty)); + /// + /// Creates a centered skew matrix from the give angles in radians and the source size. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The source image size. + /// The . + public static Matrix3x2 CreateSkewMatrixRadians(float radiansX, float radiansY, Size size) + => CreateCenteredTransformMatrix( + new Rectangle(Point.Empty, size), + Matrix3x2Extensions.CreateSkew(radiansX, radiansY, PointF.Empty)); + /// /// Gets the centered transform matrix based upon the source and destination rectangles. /// diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index 5a19b890d9..c29941d071 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -152,6 +152,82 @@ namespace SixLabors.ImageSharp.Processing public ProjectiveTransformBuilder AppendScale(Vector2 scales) => this.AppendMatrix(Matrix4x4.CreateScale(new Vector3(scales, 1F))); + /// + /// Prepends a centered skew matrix from the give angles in degrees. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The . + internal ProjectiveTransformBuilder PrependSkewDegrees(float degreesX, float degreesY) + => this.PrependSkewRadians(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY)); + + /// + /// Prepends a centered skew matrix from the give angles in radians. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The . + public ProjectiveTransformBuilder PrependSkewRadians(float radiansX, float radiansY) + => this.Prepend(size => new Matrix4x4(TransformUtils.CreateSkewMatrixRadians(radiansX, radiansY, size))); + + /// + /// Prepends a skew matrix using the given angles in degrees at the given origin. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The skew origin point. + /// The . + public ProjectiveTransformBuilder PrependSkewDegrees(float degreesX, float degreesY, Vector2 origin) + => this.PrependSkewRadians(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY), origin); + + /// + /// Prepends a skew matrix using the given angles in radians at the given origin. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The skew origin point. + /// The . + public ProjectiveTransformBuilder PrependSkewRadians(float radiansX, float radiansY, Vector2 origin) + => this.PrependMatrix(new Matrix4x4(Matrix3x2.CreateSkew(radiansX, radiansY, origin))); + + /// + /// Appends a centered skew matrix from the give angles in degrees. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The . + internal ProjectiveTransformBuilder AppendSkewDegrees(float degreesX, float degreesY) + => this.AppendSkewRadians(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY)); + + /// + /// Appends a centered skew matrix from the give angles in radians. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The . + public ProjectiveTransformBuilder AppendSkewRadians(float radiansX, float radiansY) + => this.Append(size => new Matrix4x4(TransformUtils.CreateSkewMatrixRadians(radiansX, radiansY, size))); + + /// + /// Appends a skew matrix using the given angles in degrees at the given origin. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The skew origin point. + /// The . + public ProjectiveTransformBuilder AppendSkewDegrees(float degreesX, float degreesY, Vector2 origin) + => this.AppendSkewRadians(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY), origin); + + /// + /// Appends a skew matrix using the given angles in radians at the given origin. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The skew origin point. + /// The . + public ProjectiveTransformBuilder AppendSkewRadians(float radiansX, float radiansY, Vector2 origin) + => this.AppendMatrix(new Matrix4x4(Matrix3x2.CreateSkew(radiansX, radiansY, origin))); + /// /// Prepends a translation matrix from the given vector. /// diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs index 14b8672641..70159e18ac 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs @@ -9,28 +9,55 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { public class AffineTransformBuilderTests : TransformBuilderTestBase { - protected override void AppendTranslation(AffineTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); + protected override AffineTransformBuilder CreateBuilder(Rectangle rectangle) => new AffineTransformBuilder(); - protected override void AppendScale(AffineTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); + protected override void AppendRotationDegrees(AffineTransformBuilder builder, float degrees) + => builder.AppendRotationDegrees(degrees); - protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); + protected override void AppendRotationDegrees(AffineTransformBuilder builder, float degrees, Vector2 origin) + => builder.AppendRotationDegrees(degrees, origin); - protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians, Vector2 origin) => builder.AppendRotationRadians(radians, origin); + protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) + => builder.AppendRotationRadians(radians); - protected override void AppendRotationDegrees(AffineTransformBuilder builder, float degrees) => builder.AppendRotationDegrees(degrees); + protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians, Vector2 origin) + => builder.AppendRotationRadians(radians, origin); - protected override void AppendRotationDegrees(AffineTransformBuilder builder, float degrees, Vector2 origin) => builder.AppendRotationDegrees(degrees, origin); + protected override void AppendScale(AffineTransformBuilder builder, SizeF scale) + => builder.AppendScale(scale); - protected override void PrependTranslation(AffineTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); + protected override void AppendSkewDegrees(AffineTransformBuilder builder, float degreesX, float degreesY) + => builder.AppendSkewDegrees(degreesX, degreesY); - protected override void PrependScale(AffineTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); + protected override void AppendSkewDegrees(AffineTransformBuilder builder, float degreesX, float degreesY, Vector2 origin) + => builder.AppendSkewDegrees(degreesX, degreesY, origin); - protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians); + protected override void AppendSkewRadians(AffineTransformBuilder builder, float radiansX, float radiansY) + => builder.AppendSkewRadians(radiansX, radiansY); - protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians, Vector2 origin) => - builder.PrependRotationRadians(radians, origin); + protected override void AppendSkewRadians(AffineTransformBuilder builder, float radiansX, float radiansY, Vector2 origin) + => builder.AppendSkewRadians(radiansX, radiansY, origin); - protected override AffineTransformBuilder CreateBuilder(Rectangle rectangle) => new AffineTransformBuilder(); + protected override void AppendTranslation(AffineTransformBuilder builder, PointF translate) + => builder.AppendTranslation(translate); + + protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) + => builder.PrependRotationRadians(radians); + + protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians, Vector2 origin) + => builder.PrependRotationRadians(radians, origin); + + protected override void PrependScale(AffineTransformBuilder builder, SizeF scale) + => builder.PrependScale(scale); + + protected override void PrependSkewRadians(AffineTransformBuilder builder, float radiansX, float radiansY) + => builder.PrependSkewRadians(radiansX, radiansY); + + protected override void PrependSkewRadians(AffineTransformBuilder builder, float radiansX, float radiansY, Vector2 origin) + => builder.PrependSkewRadians(radiansX, radiansY, origin); + + protected override void PrependTranslation(AffineTransformBuilder builder, PointF translate) + => builder.PrependTranslation(translate); protected override Vector2 Execute( AffineTransformBuilder builder, diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs index 9f58826cd8..d82cd1689d 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs @@ -11,24 +11,42 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { protected override ProjectiveTransformBuilder CreateBuilder(Rectangle rectangle) => new ProjectiveTransformBuilder(); - protected override void AppendTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); + protected override void AppendRotationDegrees(ProjectiveTransformBuilder builder, float degrees) => builder.AppendRotationDegrees(degrees); - protected override void AppendScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); + protected override void AppendRotationDegrees(ProjectiveTransformBuilder builder, float degrees, Vector2 origin) => builder.AppendRotationDegrees(degrees, origin); protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 origin) => builder.AppendRotationRadians(radians, origin); - protected override void AppendRotationDegrees(ProjectiveTransformBuilder builder, float degrees) => builder.AppendRotationDegrees(degrees); + protected override void AppendScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); - protected override void AppendRotationDegrees(ProjectiveTransformBuilder builder, float degrees, Vector2 origin) => builder.AppendRotationDegrees(degrees, origin); + protected override void AppendSkewDegrees(ProjectiveTransformBuilder builder, float degreesX, float degreesY) + => builder.AppendSkewDegrees(degreesX, degreesY); - protected override void PrependTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); + protected override void AppendSkewDegrees(ProjectiveTransformBuilder builder, float degreesX, float degreesY, Vector2 origin) + => builder.AppendSkewDegrees(degreesX, degreesY, origin); - protected override void PrependScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); + protected override void AppendSkewRadians(ProjectiveTransformBuilder builder, float radiansX, float radiansY) + => builder.AppendSkewRadians(radiansX, radiansY); + + protected override void AppendSkewRadians(ProjectiveTransformBuilder builder, float radiansX, float radiansY, Vector2 origin) + => builder.AppendSkewRadians(radiansX, radiansY, origin); + + protected override void AppendTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians); + protected override void PrependScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); + + protected override void PrependSkewRadians(ProjectiveTransformBuilder builder, float radiansX, float radiansY) + => builder.PrependSkewRadians(radiansX, radiansY); + + protected override void PrependSkewRadians(ProjectiveTransformBuilder builder, float radiansX, float radiansY, Vector2 origin) + => builder.PrependSkewRadians(radiansX, radiansY, origin); + + protected override void PrependTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); + protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 origin) => builder.PrependRotationRadians(radians, origin); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs index 43ad756e04..71e3b71797 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs @@ -86,17 +86,17 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms public void AppendRotationDegrees_WithoutSpecificRotationCenter_RotationIsCenteredAroundImageCenter( int width, int height, - float deg, + float degrees, float x, float y) { var size = new Size(width, height); TBuilder builder = this.CreateBuilder(size); - this.AppendRotationDegrees(builder, deg); + this.AppendRotationDegrees(builder, degrees); // TODO: We should also test CreateRotationMatrixDegrees() (and all TransformUtils stuff!) for correctness - Matrix3x2 matrix = TransformUtils.CreateRotationMatrixDegrees(deg, size); + Matrix3x2 matrix = TransformUtils.CreateRotationMatrixDegrees(degrees, size); var position = new Vector2(x, y); var expected = Vector2.Transform(position, matrix); @@ -112,7 +112,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms public void AppendRotationDegrees_WithRotationCenter( int width, int height, - float deg, + float degrees, float cx, float cy, float x, @@ -122,9 +122,63 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms TBuilder builder = this.CreateBuilder(size); var centerPoint = new Vector2(cx, cy); - this.AppendRotationDegrees(builder, deg, centerPoint); + this.AppendRotationDegrees(builder, degrees, centerPoint); - var matrix = Matrix3x2.CreateRotation(GeometryUtilities.DegreeToRadian(deg), centerPoint); + var matrix = Matrix3x2.CreateRotation(GeometryUtilities.DegreeToRadian(degrees), centerPoint); + + var position = new Vector2(x, y); + var expected = Vector2.Transform(position, matrix); + Vector2 actual = this.Execute(builder, new Rectangle(Point.Empty, size), position); + + Assert.Equal(actual, expected, Comparer); + } + + [Theory] + [InlineData(200, 100, 10, 10, 42, 84)] + [InlineData(200, 100, 100, 100, 42, 84)] + [InlineData(100, 200, -10, -10, 42, 84)] + public void AppendSkewDegrees_WithoutSpecificSkewCenter_SkewIsCenteredAroundImageCenter( + int width, + int height, + float degreesX, + float degreesY, + float x, + float y) + { + var size = new Size(width, height); + TBuilder builder = this.CreateBuilder(size); + + this.AppendSkewDegrees(builder, degreesX, degreesY); + + Matrix3x2 matrix = TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, size); + + var position = new Vector2(x, y); + var expected = Vector2.Transform(position, matrix); + Vector2 actual = this.Execute(builder, new Rectangle(Point.Empty, size), position); + Assert.Equal(actual, expected, Comparer); + } + + [Theory] + [InlineData(200, 100, 10, 10, 30, 61, 42, 84)] + [InlineData(200, 100, 100, 100, 30, 10, 20, 84)] + [InlineData(100, 200, -10, -10, 30, 20, 11, 84)] + public void AppendSkewDegrees_WithSkewCenter( + int width, + int height, + float degreesX, + float degreesY, + float cx, + float cy, + float x, + float y) + { + var size = new Size(width, height); + TBuilder builder = this.CreateBuilder(size); + + var centerPoint = new Vector2(cx, cy); + this.AppendSkewDegrees(builder, degreesX, degreesY, centerPoint); + + var matrix = Matrix3x2.CreateSkew(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY), centerPoint); var position = new Vector2(x, y); var expected = Vector2.Transform(position, matrix); @@ -144,14 +198,18 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms // Forwards this.AppendRotationRadians(b1, pi); + this.AppendSkewRadians(b1, pi, pi); this.AppendScale(b1, new SizeF(2, 0.5f)); this.AppendRotationRadians(b1, pi / 2, new Vector2(-0.5f, -0.1f)); + this.AppendSkewRadians(b1, pi, pi / 2, new Vector2(-0.5f, -0.1f)); this.AppendTranslation(b1, new PointF(123, 321)); // Backwards this.PrependTranslation(b2, new PointF(123, 321)); + this.PrependSkewRadians(b2, pi, pi / 2, new Vector2(-0.5f, -0.1f)); this.PrependRotationRadians(b2, pi / 2, new Vector2(-0.5f, -0.1f)); this.PrependScale(b2, new SizeF(2, 0.5f)); + this.PrependSkewRadians(b2, pi, pi); this.PrependRotationRadians(b2, pi); Vector2 p1 = this.Execute(b1, rectangle, new Vector2(32, 65)); @@ -180,25 +238,37 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected abstract TBuilder CreateBuilder(Rectangle rectangle); - protected abstract void AppendTranslation(TBuilder builder, PointF translate); + protected abstract void AppendRotationDegrees(TBuilder builder, float degrees); - protected abstract void AppendScale(TBuilder builder, SizeF scale); + protected abstract void AppendRotationDegrees(TBuilder builder, float degrees, Vector2 origin); protected abstract void AppendRotationRadians(TBuilder builder, float radians); protected abstract void AppendRotationRadians(TBuilder builder, float radians, Vector2 origin); - protected abstract void PrependTranslation(TBuilder builder, PointF translate); + protected abstract void AppendScale(TBuilder builder, SizeF scale); - protected abstract void PrependScale(TBuilder builder, SizeF scale); + protected abstract void AppendSkewDegrees(TBuilder builder, float degreesX, float degreesY); + + protected abstract void AppendSkewDegrees(TBuilder builder, float degreesX, float degreesY, Vector2 origin); + + protected abstract void AppendSkewRadians(TBuilder builder, float radiansX, float radiansY); + + protected abstract void AppendSkewRadians(TBuilder builder, float radiansX, float radiansY, Vector2 origin); + + protected abstract void AppendTranslation(TBuilder builder, PointF translate); protected abstract void PrependRotationRadians(TBuilder builder, float radians); protected abstract void PrependRotationRadians(TBuilder builder, float radians, Vector2 origin); - protected abstract void AppendRotationDegrees(TBuilder builder, float degrees); + protected abstract void PrependScale(TBuilder builder, SizeF scale); - protected abstract void AppendRotationDegrees(TBuilder builder, float degrees, Vector2 origin); + protected abstract void PrependSkewRadians(TBuilder builder, float radiansX, float radiansY); + + protected abstract void PrependSkewRadians(TBuilder builder, float radiansX, float radiansY, Vector2 origin); + + protected abstract void PrependTranslation(TBuilder builder, PointF translate); protected abstract Vector2 Execute(TBuilder builder, Rectangle rectangle, Vector2 sourcePoint); } From 2742e1923c369bc880d9649aa7fa3c1ebb3a92d0 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 28 Nov 2018 18:44:28 +0100 Subject: [PATCH 370/381] cleanup & undo WIP project setup --- src/ImageSharp.Drawing/ImageSharp.Drawing.csproj | 3 +-- src/ImageSharp/ImageSharp.csproj | 3 +-- ...KernelMap.cs => ResizeKernelMap.PeriodicKernelMap.cs} | 6 +++--- .../Processors/Transforms/Resize/ResizeKernelMap.cs | 2 +- tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj | 3 +-- tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 3 +-- .../Transforms/KernelMapTests.ReferenceKernelMap.cs | 6 +++--- .../Processing/Processors/Transforms/KernelMapTests.cs | 9 ++++----- 8 files changed, 15 insertions(+), 20 deletions(-) rename src/ImageSharp/Processing/Processors/Transforms/Resize/{ResizeKernelMap.MosaicKernelMap.cs => ResizeKernelMap.PeriodicKernelMap.cs} (94%) diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index 6341e1771c..1cb3f444f0 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -5,8 +5,7 @@ $(packageversion) 0.0.1 SixLabors and contributors - - netcoreapp2.1 + netstandard1.3;netstandard2.0 7.3 true true diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index e2f55e3c6a..29d29d50d8 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -5,8 +5,7 @@ $(packageversion) 0.0.1 Six Labors and contributors - - netcoreapp2.1 + netstandard1.3;netstandard2.0;netcoreapp2.1;net472 true true SixLabors.ImageSharp diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs similarity index 94% rename from src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs index e106b1ea0a..b7b581c185 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs @@ -8,20 +8,20 @@ using SixLabors.Memory; namespace SixLabors.ImageSharp.Processing.Processors.Transforms { /// - /// Contains + /// Contains /// internal partial class ResizeKernelMap { /// /// Memory-optimized where repeating rows are stored only once. /// - private sealed class MosaicKernelMap : ResizeKernelMap + private sealed class PeriodicKernelMap : ResizeKernelMap { private readonly int period; private readonly int cornerInterval; - public MosaicKernelMap( + public PeriodicKernelMap( MemoryAllocator memoryAllocator, IResampler sampler, int sourceLength, diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index ccb57114ae..011a4ffa22 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms bool useMosaic = 2 * (cornerInterval + period) < destinationSize; ResizeKernelMap result = useMosaic - ? new MosaicKernelMap( + ? new PeriodicKernelMap( memoryAllocator, sampler, sourceSize, diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 04a4541b21..a705c9bacb 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -1,7 +1,6 @@  - - netcoreapp2.1 + netcoreapp2.1;net461 Exe True SixLabors.ImageSharp.Benchmarks diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 75ac7450c8..86c1a7a259 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -1,7 +1,6 @@  - - netcoreapp2.1 + net462;net472;netcoreapp2.1 True latest full diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs index f7c3b27e5a..12c7016096 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms scale = 1F; } - float radius = MathF.Ceiling(scale * sampler.Radius); + float radius = (float)Math.Ceiling(scale * sampler.Radius); var result = new List(); @@ -42,13 +42,13 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms float center = ((i + .5F) * ratio) - .5F; // Keep inside bounds. - int left = (int)MathF.Ceiling(center - radius); + int left = (int)Math.Ceiling(center - radius); if (left < 0) { left = 0; } - int right = (int)MathF.Floor(center + radius); + int right = (int)Math.Floor(center + radius); if (right > sourceSize - 1) { right = sourceSize - 1; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index af98b99521..962c599e6a 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -1,12 +1,11 @@ -using System; -using System.IO; -using System.Runtime.InteropServices; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; 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; From 03324e3c218ee97ce13f2d7cecf9dd4d2ef9cf58 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 28 Nov 2018 23:20:57 +0100 Subject: [PATCH 371/381] additional extensive testing --- .../KernelMapTests.ReferenceKernelMap.cs | 21 +++--- .../Processors/Transforms/KernelMapTests.cs | 70 +++++++++++++++++-- 2 files changed, 76 insertions(+), 15 deletions(-) diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs index 12c7016096..9a7052b5a8 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using SixLabors.ImageSharp.Processing.Processors.Transforms; @@ -25,21 +26,21 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms public static ReferenceKernelMap Calculate(IResampler sampler, int destinationSize, int sourceSize, bool normalize = true) { - float ratio = (float)sourceSize / destinationSize; - float scale = ratio; + double ratio = (double)sourceSize / destinationSize; + double scale = ratio; if (scale < 1F) { scale = 1F; } - float radius = (float)Math.Ceiling(scale * sampler.Radius); + double radius = (double)Math.Ceiling(scale * sampler.Radius); var result = new List(); for (int i = 0; i < destinationSize; i++) { - float center = ((i + .5F) * ratio) - .5F; + double center = ((i + .5) * ratio) - .5; // Keep inside bounds. int left = (int)Math.Ceiling(center - radius); @@ -54,20 +55,18 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms right = sourceSize - 1; } - float sum = 0; + double sum = 0; - float[] values = new float[right - left + 1]; + double[] values = new double[right - left + 1]; for (int j = left; j <= right; j++) { - float weight = sampler.GetValue((j - center) / scale); + double weight = sampler.GetValue((float)((j - center) / scale)); sum += weight; values[j - left] = weight; } - result.Add(new ReferenceKernel(left, values)); - if (sum > 0 && normalize) { for (int w = 0; w < values.Length; w++) @@ -75,6 +74,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms values[w] /= sum; } } + + float[] floatVals = values.Select(v => (float)v).ToArray(); + + result.Add(new ReferenceKernel(left, floatVals)); } return new ReferenceKernelMap(result.ToArray()); diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index 962c599e6a..dfbd7a28be 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -2,6 +2,9 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; using System.Text; using SixLabors.ImageSharp.Processing; @@ -58,6 +61,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { nameof(KnownResamplers.Lanczos8), 10, 100 }, }; + public static TheoryData GeneratedImageResizeData = + GenerateImageResizeData(); + + [Theory] [MemberData(nameof(KernelMapData))] public void PrintNonNormalizedKernelMap(string resamplerName, int srcSize, int destSize) @@ -71,7 +78,21 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms [Theory] [MemberData(nameof(KernelMapData))] + //[MemberData(nameof(GeneratedImageResizeData))] public void KernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) + { + VerifyKernelMapContentIsCorrect(resamplerName, srcSize, destSize); + } + + [Theory] + [MemberData(nameof(GeneratedImageResizeData))] + public void KernelMapContentIsCorrect_ExtendedGeneratedValues(string resamplerName, int srcSize, int destSize) + { + VerifyKernelMapContentIsCorrect(resamplerName, srcSize, destSize); + } + + + private static void VerifyKernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) { IResampler resampler = TestUtils.GetResampler(resamplerName); @@ -79,8 +100,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms var kernelMap = ResizeKernelMap.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator); #if DEBUG - this.Output.WriteLine($"Expected KernelMap:\n{PrintKernelMap(referenceMap)}\n"); - this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); + // this.Output.WriteLine($"Expected KernelMap:\n{PrintKernelMap(referenceMap)}\n"); + // this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); #endif for (int i = 0; i < kernelMap.DestinationLength; i++) @@ -89,14 +110,18 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms ReferenceKernel referenceKernel = referenceMap.GetKernel(i); - Assert.Equal(referenceKernel.Length, kernel.Length); - Assert.Equal(referenceKernel.Left, kernel.Left); + Assert.True( + referenceKernel.Length == kernel.Length, + $"referenceKernel.Length != kernel.Length: {referenceKernel.Length} != {kernel.Length}"); + Assert.True( + referenceKernel.Left == kernel.Left, + $"referenceKernel.Left != kernel.Left: {referenceKernel.Left} != {kernel.Left}"); float[] expectedValues = referenceKernel.Values; Span actualValues = kernel.Values; - + Assert.Equal(expectedValues.Length, actualValues.Length); - var comparer = new ApproximateFloatComparer(1e-4f); + var comparer = new ApproximateFloatComparer(1e-6f); for (int x = 0; x < expectedValues.Length; x++) { @@ -145,5 +170,38 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms return bld.ToString(); } + + + private static TheoryData GenerateImageResizeData() + { + var result = new TheoryData(); + + string[] resamplerNames = typeof(KnownResamplers).GetProperties(BindingFlags.Public | BindingFlags.Static) + .Select(p => p.Name).ToArray(); + + int[] dimensionVals = + { + // Arbitrary, small dimensions: + 9, 10, 11, 13, 49, 50, 53, 99, 100, 199, 200, 201, 299, 300, 301, + + // Typical image sizes: + 640, 480, 800, 600, 1024, 768, 1280, 960, 1536, 1180, 1600, 1200, 2048, 1536, 2240, 1680, 2560, + 1920, 3032, 2008, 3072, 2304, 3264, 2448 + }; + + IOrderedEnumerable<(int s, int d)> source2Dest = dimensionVals + .SelectMany(s => dimensionVals.Select(d => (s, d))) + .OrderBy(x => x.s + x.d); + + foreach (string resampler in resamplerNames) + { + foreach ((int s, int d) x in source2Dest) + { + result.Add(resampler, x.s, x.d); + } + } + + return result; + } } } \ No newline at end of file From ee1f398b1e13b76eb3a244ddfaed0640b5a58526 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 28 Nov 2018 23:21:30 +0100 Subject: [PATCH 372/381] use double precision in KernelMap calculations --- .../Transforms/Resize/ResizeKernel.cs | 10 +++ .../ResizeKernelMap.PeriodicKernelMap.cs | 8 +-- .../Transforms/Resize/ResizeKernelMap.cs | 66 ++++++++++--------- 3 files changed, 50 insertions(+), 34 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs index 04bf6c3a44..f349634ac0 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs @@ -80,5 +80,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { return new ResizeKernel(left, this.bufferPtr, this.Length); } + + internal void Fill(Span values) + { + DebugGuard.IsTrue(values.Length == this.Length, nameof(values), "ResizeKernel.Fill: values.Length != this.Length!"); + + for (int i = 0; i < this.Length; i++) + { + this.Values[i] = (float)values[i]; + } + } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs index b7b581c185..e0f5ad2613 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs @@ -26,8 +26,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms IResampler sampler, int sourceLength, int destinationLength, - float ratio, - float scale, + double ratio, + double scale, int radius, int period, int cornerInterval) @@ -62,8 +62,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int bottomStartDest = this.DestinationLength - this.cornerInterval; for (int i = startOfFirstRepeatedMosaic; i < bottomStartDest; i++) { - float center = ((i + .5F) * this.ratio) - .5F; - int left = (int)MathF.Ceiling(center - this.radius); + double center = ((i + .5) * this.ratio) - .5; + int left = (int)Math.Ceiling(center - this.radius); ResizeKernel kernel = this.kernels[i - this.period]; this.kernels[i] = kernel.AlterLeftValue(left); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index 011a4ffa22..4cd9928d30 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -17,13 +17,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// internal partial class ResizeKernelMap : IDisposable { + private readonly MemoryAllocator memoryAllocator; + private readonly IResampler sampler; private readonly int sourceLength; - private readonly float ratio; + private readonly double ratio; - private readonly float scale; + private readonly double scale; private readonly int radius; @@ -39,10 +41,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int sourceLength, int destinationLength, int bufferHeight, - float ratio, - float scale, + double ratio, + double scale, int radius) { + this.memoryAllocator = memoryAllocator; this.sampler = sampler; this.ratio = ratio; this.scale = scale; @@ -95,19 +98,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int sourceSize, MemoryAllocator memoryAllocator) { - float ratio = (float)sourceSize / destinationSize; - float scale = ratio; + double ratio = (double)sourceSize / destinationSize; + double scale = ratio; if (scale < 1F) { scale = 1F; } - int radius = (int)MathF.Ceiling(scale * sampler.Radius); + int radius = (int)Math.Ceiling(scale * sampler.Radius); int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize; - float center0 = (ratio - 1) * 0.5f; - float firstNonNegativeLeftVal = (radius - center0 - 1) / ratio; - int cornerInterval = (int)MathF.Ceiling(firstNonNegativeLeftVal); + double center0 = (ratio - 1) * 0.5f; + double firstNonNegativeLeftVal = (radius - center0 - 1) / ratio; + int cornerInterval = (int)Math.Ceiling(firstNonNegativeLeftVal); // corner case for cornerInteval: if (firstNonNegativeLeftVal == cornerInterval) @@ -159,45 +162,48 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// private ResizeKernel BuildKernel(int destRowIndex, int dataRowIndex) { - float center = ((destRowIndex + .5F) * this.ratio) - .5F; + double center = ((destRowIndex + .5) * this.ratio) - .5; // Keep inside bounds. - int left = (int)MathF.Ceiling(center - this.radius); + int left = (int)Math.Ceiling(center - this.radius); if (left < 0) { left = 0; } - int right = (int)MathF.Floor(center + this.radius); + int right = (int)Math.Floor(center + this.radius); if (right > this.sourceLength - 1) { right = this.sourceLength - 1; } - float sum = 0; - ResizeKernel kernel = this.CreateKernel(dataRowIndex, left, right); - ref float kernelBaseRef = ref MemoryMarshal.GetReference(kernel.Values); - - for (int j = left; j <= right; j++) + using (IMemoryOwner tempBuffer = this.memoryAllocator.Allocate(kernel.Length)) { - float value = this.sampler.GetValue((j - center) / this.scale); - sum += value; + Span kernelValues = tempBuffer.GetSpan(); + double sum = 0; - // weights[j - left] = weight: - Unsafe.Add(ref kernelBaseRef, j - left) = value; - } + for (int j = left; j <= right; j++) + { + double value = this.sampler.GetValue((float)((j - center) / this.scale)); + sum += value; - // Normalize, best to do it here rather than in the pixel loop later on. - if (sum > 0) - { - for (int w = 0; w < kernel.Length; w++) + kernelValues[j - left] = value; + } + + // Normalize, best to do it here rather than in the pixel loop later on. + if (sum > 0) { - // weights[w] = weights[w] / sum: - ref float kRef = ref Unsafe.Add(ref kernelBaseRef, w); - kRef /= sum; + for (int j = 0; j < kernel.Length; j++) + { + // weights[w] = weights[w] / sum: + ref double kRef = ref kernelValues[j]; + kRef /= sum; + } } + + kernel.Fill(kernelValues); } return kernel; From 97357b45e461a67e6cbe7c437c86cab3c5574d56 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 29 Nov 2018 01:05:07 +0100 Subject: [PATCH 373/381] cherry pick test cases from auto-generated set --- .../Processors/Transforms/KernelMapTests.cs | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index dfbd7a28be..d0ff62a911 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -59,6 +59,30 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { nameof(KnownResamplers.Lanczos8), 100, 10 }, { nameof(KnownResamplers.Lanczos8), 100, 80 }, { nameof(KnownResamplers.Lanczos8), 10, 100 }, + + // Accuracy-related regression-test cases cherry-picked from GeneratedImageResizeData + { nameof(KnownResamplers.Box), 201, 100 }, + { nameof(KnownResamplers.Box), 199, 99 }, + { nameof(KnownResamplers.Box), 10, 299 }, + { nameof(KnownResamplers.Box), 299, 10 }, + { nameof(KnownResamplers.Box), 301, 300 }, + { nameof(KnownResamplers.Box), 1180, 480 }, + + { nameof(KnownResamplers.Lanczos2), 3264, 3032 }, + + { nameof(KnownResamplers.Bicubic), 1280, 2240 }, + { nameof(KnownResamplers.Bicubic), 1920, 1680 }, + { nameof(KnownResamplers.Bicubic), 3072, 2240 }, + + { nameof(KnownResamplers.Welch), 300, 2008 }, + + // ResizeKernel.Length -related regression tests cherry-picked from GeneratedImageResizeData + { nameof(KnownResamplers.Bicubic), 10, 50 }, + { nameof(KnownResamplers.Bicubic), 49, 301 }, + { nameof(KnownResamplers.Bicubic), 301, 49 }, + { nameof(KnownResamplers.Bicubic), 1680, 1200 }, + { nameof(KnownResamplers.Box), 13, 299 }, + { nameof(KnownResamplers.Lanczos5), 3032, 600 }, }; public static TheoryData GeneratedImageResizeData = @@ -78,18 +102,21 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms [Theory] [MemberData(nameof(KernelMapData))] - //[MemberData(nameof(GeneratedImageResizeData))] public void KernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) { VerifyKernelMapContentIsCorrect(resamplerName, srcSize, destSize); } + // Comprehensive but expensive tests, for KernelMap generation + // Enabling them can kill your IDE: +#if false [Theory] [MemberData(nameof(GeneratedImageResizeData))] public void KernelMapContentIsCorrect_ExtendedGeneratedValues(string resamplerName, int srcSize, int destSize) { VerifyKernelMapContentIsCorrect(resamplerName, srcSize, destSize); } +#endif private static void VerifyKernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) @@ -103,6 +130,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms // this.Output.WriteLine($"Expected KernelMap:\n{PrintKernelMap(referenceMap)}\n"); // this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); #endif + var comparer = new ApproximateFloatComparer(1e-6f); for (int i = 0; i < kernelMap.DestinationLength; i++) { @@ -121,7 +149,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms Assert.Equal(expectedValues.Length, actualValues.Length); - var comparer = new ApproximateFloatComparer(1e-6f); + for (int x = 0; x < expectedValues.Length; x++) { @@ -177,7 +205,9 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms var result = new TheoryData(); string[] resamplerNames = typeof(KnownResamplers).GetProperties(BindingFlags.Public | BindingFlags.Static) - .Select(p => p.Name).ToArray(); + .Select(p => p.Name) + .Where(name => name != nameof(KnownResamplers.NearestNeighbor)) + .ToArray(); int[] dimensionVals = { From 3189c91563f3a4cb805b68137e5f4dd11c4b98e5 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 29 Nov 2018 02:34:49 +0100 Subject: [PATCH 374/381] introduce TolerantMath --- src/ImageSharp/Common/Helpers/TolerantMath.cs | 75 ++++++++++ .../Transforms/Resize/ResizeKernelMap.cs | 47 ++++--- .../Helpers/ImageMathsTests.cs | 3 +- .../Helpers/TolerantMathTests.cs | 130 ++++++++++++++++++ .../KernelMapTests.ReferenceKernelMap.cs | 6 + .../Processors/Transforms/KernelMapTests.cs | 15 +- 6 files changed, 243 insertions(+), 33 deletions(-) create mode 100644 src/ImageSharp/Common/Helpers/TolerantMath.cs create mode 100644 tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs diff --git a/src/ImageSharp/Common/Helpers/TolerantMath.cs b/src/ImageSharp/Common/Helpers/TolerantMath.cs new file mode 100644 index 0000000000..b9b3b8ea13 --- /dev/null +++ b/src/ImageSharp/Common/Helpers/TolerantMath.cs @@ -0,0 +1,75 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp +{ + /// + /// Implements math operations using tolerant comparison. + /// + internal struct TolerantMath + { + private readonly double epsilon; + + private readonly double negEpsilon; + + public TolerantMath(double epsilon) + { + DebugGuard.MustBeGreaterThan(epsilon, 0, nameof(epsilon)); + + this.epsilon = epsilon; + this.negEpsilon = -epsilon; + } + + public static TolerantMath Default { get; } = new TolerantMath(1e-8); + + /// + /// == 0 + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool IsZero(double a) => a > this.negEpsilon && a < this.epsilon; + + /// + /// > 0 + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool IsPositive(double a) => a > this.epsilon; + + /// + /// < 0 + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool IsNegative(double a) => a < this.negEpsilon; + + /// + /// == + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool AreEqual(double a, double b) => this.IsZero(a - b); + + /// + /// > + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool IsGreater(double a, double b) => a > b + this.epsilon; + + /// + /// < + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool IsLess(double a, double b) => a < b - this.epsilon; + + /// + /// >= + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool IsGreaterOrEqual(double a, double b) => a >= b - this.epsilon; + + /// + /// <= + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool IsLessOrEqual(double a, double b) => b >= a - this.epsilon; + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index 4cd9928d30..468e0d8447 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -17,8 +17,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// internal partial class ResizeKernelMap : IDisposable { - private readonly MemoryAllocator memoryAllocator; - private readonly IResampler sampler; private readonly int sourceLength; @@ -35,6 +33,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private readonly ResizeKernel[] kernels; + // To avoid both GC allocations, and MemoryAllocator ceremony: + private readonly double[] tempValues; + private ResizeKernelMap( MemoryAllocator memoryAllocator, IResampler sampler, @@ -45,7 +46,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms double scale, int radius) { - this.memoryAllocator = memoryAllocator; this.sampler = sampler; this.ratio = ratio; this.scale = scale; @@ -56,6 +56,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.data = memoryAllocator.Allocate2D(maxWidth, bufferHeight, AllocationOptions.Clean); this.pinHandle = this.data.Memory.Pin(); this.kernels = new ResizeKernel[destinationLength]; + this.tempValues = new double[maxWidth]; } /// @@ -113,7 +114,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int cornerInterval = (int)Math.Ceiling(firstNonNegativeLeftVal); // corner case for cornerInteval: - if (firstNonNegativeLeftVal == cornerInterval) + // TODO: Implement library-wide utils for tolerant comparison + if (Math.Abs(firstNonNegativeLeftVal - cornerInterval) < 1e-8) { cornerInterval++; } @@ -179,33 +181,30 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms ResizeKernel kernel = this.CreateKernel(dataRowIndex, left, right); - using (IMemoryOwner tempBuffer = this.memoryAllocator.Allocate(kernel.Length)) - { - Span kernelValues = tempBuffer.GetSpan(); - double sum = 0; + Span kernelValues = this.tempValues.AsSpan().Slice(0, kernel.Length); + double sum = 0; - for (int j = left; j <= right; j++) - { - double value = this.sampler.GetValue((float)((j - center) / this.scale)); - sum += value; + for (int j = left; j <= right; j++) + { + double value = this.sampler.GetValue((float)((j - center) / this.scale)); + sum += value; - kernelValues[j - left] = value; - } + kernelValues[j - left] = value; + } - // Normalize, best to do it here rather than in the pixel loop later on. - if (sum > 0) + // Normalize, best to do it here rather than in the pixel loop later on. + if (sum > 0) + { + for (int j = 0; j < kernel.Length; j++) { - for (int j = 0; j < kernel.Length; j++) - { - // weights[w] = weights[w] / sum: - ref double kRef = ref kernelValues[j]; - kRef /= sum; - } + // weights[w] = weights[w] / sum: + ref double kRef = ref kernelValues[j]; + kRef /= sum; } - - kernel.Fill(kernelValues); } + kernel.Fill(kernelValues); + return kernel; } diff --git a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs index 75ef611a5c..018fabd982 100644 --- a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs @@ -2,11 +2,10 @@ // Licensed under the Apache License, Version 2.0. using System; +using Xunit; namespace SixLabors.ImageSharp.Tests.Helpers { - using Xunit; - public class ImageMathsTests { [Theory] diff --git a/tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs b/tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs new file mode 100644 index 0000000000..d488d6491d --- /dev/null +++ b/tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs @@ -0,0 +1,130 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; + +using Xunit; +// ReSharper disable InconsistentNaming + +namespace SixLabors.ImageSharp.Tests.Helpers +{ + public class TolerantMathTests + { + private readonly TolerantMath tolerantMath = new TolerantMath(0.1); + + [Theory] + [InlineData(0)] + [InlineData(0.01)] + [InlineData(-0.05)] + public void IsZero_WhenTrue(double a) + { + Assert.True(this.tolerantMath.IsZero(a)); + } + + [Theory] + [InlineData(0.11)] + [InlineData(-0.101)] + [InlineData(42)] + public void IsZero_WhenFalse(double a) + { + Assert.False(this.tolerantMath.IsZero(a)); + } + + [Theory] + [InlineData(0.11)] + [InlineData(100)] + public void IsPositive_WhenTrue(double a) + { + Assert.True(this.tolerantMath.IsPositive(a)); + } + + [Theory] + [InlineData(0.09)] + [InlineData(-0.1)] + [InlineData(-1000)] + public void IsPositive_WhenFalse(double a) + { + Assert.False(this.tolerantMath.IsPositive(a)); + } + + [Theory] + [InlineData(-0.11)] + [InlineData(-100)] + public void IsNegative_WhenTrue(double a) + { + Assert.True(this.tolerantMath.IsNegative(a)); + } + + [Theory] + [InlineData(-0.09)] + [InlineData(0.1)] + [InlineData(1000)] + public void IsNegative_WhenFalse(double a) + { + Assert.False(this.tolerantMath.IsNegative(a)); + } + + [Theory] + [InlineData(4.2, 4.2)] + [InlineData(4.2, 4.25)] + [InlineData(-Math.PI, -Math.PI + 0.05)] + [InlineData(999999.2, 999999.25)] + public void AreEqual_WhenTrue(double a, double b) + { + Assert.True(this.tolerantMath.AreEqual(a, b)); + } + + [Theory] + [InlineData(1, 2)] + [InlineData(-1000000, -1000000.2)] + public void AreEqual_WhenFalse(double a, double b) + { + Assert.False(this.tolerantMath.AreEqual(a, b)); + } + + [Theory] + [InlineData(2, 1.8)] + [InlineData(-20, -20.2)] + [InlineData(0.1, -0.1)] + [InlineData(100, 10)] + public void IsGreater_IsLess_WhenTrue(double a, double b) + { + Assert.True(this.tolerantMath.IsGreater(a, b)); + Assert.True(this.tolerantMath.IsLess(b, a)); + } + + [Theory] + [InlineData(2, 1.95)] + [InlineData(-20, -20.02)] + [InlineData(0.01, -0.01)] + [InlineData(999999, 999999.09)] + public void IsGreater_IsLess_WhenFalse(double a, double b) + { + Assert.False(this.tolerantMath.IsGreater(a, b)); + Assert.False(this.tolerantMath.IsLess(b, a)); + } + + [Theory] + [InlineData(3, 2)] + [InlineData(3, 2.99)] + [InlineData(2.99, 3)] + [InlineData(-5, -6)] + [InlineData(-5, -5.05)] + [InlineData(-5.05, -5)] + public void IsGreaterOrEqual_IsLessOrEqual_WhenTrue(double a, double b) + { + Assert.True(this.tolerantMath.IsGreaterOrEqual(a, b)); + Assert.True(this.tolerantMath.IsLessOrEqual(b, a)); + } + + [Theory] + [InlineData(2, 3)] + [InlineData(2.89, 3)] + [InlineData(-3, -2.89)] + public void IsGreaterOrEqual_IsLessOrEqual_WhenFalse(double a, double b) + { + Assert.False(this.tolerantMath.IsGreaterOrEqual(a, b)); + Assert.False(this.tolerantMath.IsLessOrEqual(b, a)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs index 9a7052b5a8..31907b06d3 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using SixLabors.ImageSharp.Processing.Processors.Transforms; @@ -40,6 +41,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms for (int i = 0; i < destinationSize; i++) { + if (i == 21 || i == 64) + { + Debug.Print("lol"); + } + double center = ((i + .5) * ratio) - .5; // Keep inside bounds. diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index d0ff62a911..dc7a441e99 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -104,22 +104,23 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms [MemberData(nameof(KernelMapData))] public void KernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) { - VerifyKernelMapContentIsCorrect(resamplerName, srcSize, destSize); + this.VerifyKernelMapContentIsCorrect(resamplerName, srcSize, destSize); } - // Comprehensive but expensive tests, for KernelMap generation - // Enabling them can kill your IDE: + // Comprehensive but expensive tests, for ResizeKernelMap. + // Enabling them can kill you, but sometimes you have to wear the burden! + // AppVeyor will never follow you to these shadows of Mordor. #if false [Theory] [MemberData(nameof(GeneratedImageResizeData))] public void KernelMapContentIsCorrect_ExtendedGeneratedValues(string resamplerName, int srcSize, int destSize) { - VerifyKernelMapContentIsCorrect(resamplerName, srcSize, destSize); + this.VerifyKernelMapContentIsCorrect(resamplerName, srcSize, destSize); } #endif - private static void VerifyKernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) + private void VerifyKernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) { IResampler resampler = TestUtils.GetResampler(resamplerName); @@ -127,8 +128,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms var kernelMap = ResizeKernelMap.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator); #if DEBUG - // this.Output.WriteLine($"Expected KernelMap:\n{PrintKernelMap(referenceMap)}\n"); - // this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); + this.Output.WriteLine($"Expected KernelMap:\n{PrintKernelMap(referenceMap)}\n"); + this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); #endif var comparer = new ApproximateFloatComparer(1e-6f); From 49ef404552c15929c5d83a4e93b361df4325c11a Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 29 Nov 2018 02:54:31 +0100 Subject: [PATCH 375/381] TolerantMath: implemented Floor and Ceiling --- src/ImageSharp/Common/Helpers/TolerantMath.cs | 28 +++++++++++++- .../Helpers/TolerantMathTests.cs | 38 +++++++++++++++++++ .../ImageSharp.Tests/ImageSharp.Tests.csproj | 3 +- 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/TolerantMath.cs b/src/ImageSharp/Common/Helpers/TolerantMath.cs index b9b3b8ea13..d95aea9de2 100644 --- a/src/ImageSharp/Common/Helpers/TolerantMath.cs +++ b/src/ImageSharp/Common/Helpers/TolerantMath.cs @@ -1,12 +1,14 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp { /// - /// Implements math operations using tolerant comparison. + /// Implements basic math operations using tolerant comparison + /// whenever an equality check is needed. /// internal struct TolerantMath { @@ -71,5 +73,29 @@ namespace SixLabors.ImageSharp /// [MethodImpl(InliningOptions.ShortMethod)] public bool IsLessOrEqual(double a, double b) => b >= a - this.epsilon; + + [MethodImpl(InliningOptions.ShortMethod)] + public double Ceiling(double a) + { + double rem = Math.IEEERemainder(a, 1); + if (this.IsZero(rem)) + { + return Math.Round(a); + } + + return Math.Ceiling(a); + } + + [MethodImpl(InliningOptions.ShortMethod)] + public double Floor(double a) + { + double rem = Math.IEEERemainder(a, 1); + if (this.IsZero(rem)) + { + return Math.Round(a); + } + + return Math.Floor(a); + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs b/tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs index d488d6491d..6c7a1f2752 100644 --- a/tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs +++ b/tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs @@ -126,5 +126,43 @@ namespace SixLabors.ImageSharp.Tests.Helpers Assert.False(this.tolerantMath.IsGreaterOrEqual(a, b)); Assert.False(this.tolerantMath.IsLessOrEqual(b, a)); } + + [Theory] + [InlineData(3.5, 4.0)] + [InlineData(3.89, 4.0)] + [InlineData(4.09, 4.0)] + [InlineData(4.11, 5.0)] + [InlineData(0.11, 1)] + [InlineData(0.05, 0)] + [InlineData(-0.5, 0)] + [InlineData(-0.95, -1)] + [InlineData(-1.05, -1)] + [InlineData(-1.5, -1)] + public void Ceiling(double value, double expected) + { + double actual = this.tolerantMath.Ceiling(value); + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(1, 1)] + [InlineData(0.99, 1)] + [InlineData(0.5, 0)] + [InlineData(0.01, 0)] + [InlineData(-0.09, 0)] + [InlineData(-0.11, -1)] + [InlineData(-100.11, -101)] + [InlineData(-100.09, -100)] + public void Floor(double value, double expected) + { + double plz1 = Math.IEEERemainder(1.1, 1); + double plz2 = Math.IEEERemainder(0.9, 1); + + double plz3 = Math.IEEERemainder(-1.1, 1); + double plz4 = Math.IEEERemainder(-0.9, 1); + + double actual = this.tolerantMath.Floor(value); + Assert.Equal(expected, actual); + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 86c1a7a259..75ac7450c8 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -1,6 +1,7 @@  - net462;net472;netcoreapp2.1 + + netcoreapp2.1 True latest full From b4271cc20d17b148b9e312211b2b339a1d172b98 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 29 Nov 2018 03:05:38 +0100 Subject: [PATCH 376/381] robust ResizeKernelMap calculations using TolerantMath --- .../Resize/ResizeKernelMap.PeriodicKernelMap.cs | 2 +- .../Transforms/Resize/ResizeKernelMap.cs | 15 ++++++++------- tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 3 +-- .../KernelMapTests.ReferenceKernelMap.cs | 16 +++++++++------- .../Processors/Transforms/KernelMapTests.cs | 1 - 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs index e0f5ad2613..4b81aaa64e 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int i = startOfFirstRepeatedMosaic; i < bottomStartDest; i++) { double center = ((i + .5) * this.ratio) - .5; - int left = (int)Math.Ceiling(center - this.radius); + int left = (int)TolerantMath.Ceiling(center - this.radius); ResizeKernel kernel = this.kernels[i - this.period]; this.kernels[i] = kernel.AlterLeftValue(left); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index 468e0d8447..347aaf0be0 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -17,6 +17,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// internal partial class ResizeKernelMap : IDisposable { + private static readonly TolerantMath TolerantMath = TolerantMath.Default; + private readonly IResampler sampler; private readonly int sourceLength; @@ -107,15 +109,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms scale = 1F; } - int radius = (int)Math.Ceiling(scale * sampler.Radius); + int radius = (int)TolerantMath.Ceiling(scale * sampler.Radius); int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize; - double center0 = (ratio - 1) * 0.5f; + double center0 = (ratio - 1) * 0.5; double firstNonNegativeLeftVal = (radius - center0 - 1) / ratio; - int cornerInterval = (int)Math.Ceiling(firstNonNegativeLeftVal); + int cornerInterval = (int)TolerantMath.Ceiling(firstNonNegativeLeftVal); // corner case for cornerInteval: - // TODO: Implement library-wide utils for tolerant comparison - if (Math.Abs(firstNonNegativeLeftVal - cornerInterval) < 1e-8) + if (TolerantMath.AreEqual(firstNonNegativeLeftVal, cornerInterval)) { cornerInterval++; } @@ -167,13 +168,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms double center = ((destRowIndex + .5) * this.ratio) - .5; // Keep inside bounds. - int left = (int)Math.Ceiling(center - this.radius); + int left = (int)TolerantMath.Ceiling(center - this.radius); if (left < 0) { left = 0; } - int right = (int)Math.Floor(center + this.radius); + int right = (int)TolerantMath.Floor(center + this.radius); if (right > this.sourceLength - 1) { right = this.sourceLength - 1; diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 75ac7450c8..86c1a7a259 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -1,7 +1,6 @@  - - netcoreapp2.1 + net462;net472;netcoreapp2.1 True latest full diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs index 31907b06d3..54ac239ae9 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs @@ -35,27 +35,29 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms scale = 1F; } - double radius = (double)Math.Ceiling(scale * sampler.Radius); + TolerantMath tolerantMath = TolerantMath.Default; + + double radius = tolerantMath.Ceiling(scale * sampler.Radius); var result = new List(); for (int i = 0; i < destinationSize; i++) { - if (i == 21 || i == 64) - { - Debug.Print("lol"); - } + //if (i == 21 || i == 64) + //{ + // Debug.Print("lol"); + //} double center = ((i + .5) * ratio) - .5; // Keep inside bounds. - int left = (int)Math.Ceiling(center - radius); + int left = (int)tolerantMath.Ceiling(center - radius); if (left < 0) { left = 0; } - int right = (int)Math.Floor(center + radius); + int right = (int)tolerantMath.Floor(center + radius); if (right > sourceSize - 1) { right = sourceSize - 1; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index dc7a441e99..c9f20cd272 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -119,7 +119,6 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } #endif - private void VerifyKernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) { IResampler resampler = TestUtils.GetResampler(resamplerName); From 25195a74f14f4cf0d52422422a134920f55332c0 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 29 Nov 2018 03:54:29 +0100 Subject: [PATCH 377/381] update submodule, skip debug-only test case --- .../Processing/Processors/Transforms/KernelMapTests.cs | 6 +++++- tests/Images/External | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index c9f20cd272..783c3c5af6 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -60,6 +60,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { nameof(KnownResamplers.Lanczos8), 100, 80 }, { nameof(KnownResamplers.Lanczos8), 10, 100 }, + // Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_Box-0.5: + { nameof(KnownResamplers.Box), 378, 149 }, + { nameof(KnownResamplers.Box), 349, 174 }, + // Accuracy-related regression-test cases cherry-picked from GeneratedImageResizeData { nameof(KnownResamplers.Box), 201, 100 }, { nameof(KnownResamplers.Box), 199, 99 }, @@ -89,7 +93,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms GenerateImageResizeData(); - [Theory] + [Theory(Skip = "Only for debugging and development")] [MemberData(nameof(KernelMapData))] public void PrintNonNormalizedKernelMap(string resamplerName, int srcSize, int destSize) { diff --git a/tests/Images/External b/tests/Images/External index ed8a7b0b6f..5b18d8c95a 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit ed8a7b0b6fe1b2e2a7c822aa617103ae31192655 +Subproject commit 5b18d8c95acffb773012881870ba6f521ba13128 From d4ff2a44f02ac703e32575a81f764805c257389b Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 29 Nov 2018 04:14:46 +0100 Subject: [PATCH 378/381] remove outdated TODO note --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 45cb52fd95..9e03c0d3d8 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -99,7 +99,6 @@ 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) { From 77e72c8000653fd806c6c4af412d27a8f436b050 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 29 Nov 2018 14:51:06 +0100 Subject: [PATCH 379/381] test code cleanup --- ...esizeKernelMapTests.ReferenceKernelMap.cs} | 12 ++++------ ...nelMapTests.cs => ResizeKernelMapTests.cs} | 4 ++-- .../Processors/Transforms/ResizeTests.cs | 23 ------------------- 3 files changed, 6 insertions(+), 33 deletions(-) rename tests/ImageSharp.Tests/Processing/Processors/Transforms/{KernelMapTests.ReferenceKernelMap.cs => ResizeKernelMapTests.ReferenceKernelMap.cs} (93%) rename tests/ImageSharp.Tests/Processing/Processors/Transforms/{KernelMapTests.cs => ResizeKernelMapTests.cs} (98%) diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.ReferenceKernelMap.cs similarity index 93% rename from tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs rename to tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.ReferenceKernelMap.cs index 54ac239ae9..7d842c4e1e 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.ReferenceKernelMap.cs @@ -1,13 +1,14 @@ -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using SixLabors.ImageSharp.Processing.Processors.Transforms; namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { - public partial class KernelMapTests + public partial class ResizeKernelMapTests { /// /// Simplified reference implementation for functionality. @@ -43,11 +44,6 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms for (int i = 0; i < destinationSize; i++) { - //if (i == 21 || i == 64) - //{ - // Debug.Print("lol"); - //} - double center = ((i + .5) * ratio) - .5; // Keep inside bounds. diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs similarity index 98% rename from tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs rename to tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs index 783c3c5af6..08b2949139 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs @@ -15,11 +15,11 @@ using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { - public partial class KernelMapTests + public partial class ResizeKernelMapTests { private ITestOutputHelper Output { get; } - public KernelMapTests(ITestOutputHelper output) + public ResizeKernelMapTests(ITestOutputHelper output) { this.Output = output; } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index 839d26e71c..b4aff53e82 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs @@ -58,29 +58,6 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } } - // TODO: Merge with the previous theory + add test images - [Theory] - [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.Bicubic), 1)] - [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.Bicubic), 10)] - [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.Lanczos3), 10)] - [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.Lanczos8), 10)] - [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.NearestNeighbor), 10)] - [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32, nameof(KnownResamplers.NearestNeighbor), 1)] - [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32, nameof(KnownResamplers.NearestNeighbor), 5)] - [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32, nameof(KnownResamplers.Bicubic), 5)] - public void ScaleUp(TestImageProvider provider, string samplerName, float ratio) - where TPixel : struct, IPixel - { - using (Image image = provider.GetImage()) - { - SizeF newSize = image.Size() * ratio; - image.Mutate(x => x.Resize((Size)newSize, TestUtils.GetResampler(samplerName), false)); - FormattableString details = $"{samplerName}_{ratio.ToString(System.Globalization.CultureInfo.InvariantCulture)}"; - - image.DebugSave(provider, details); - } - } - [Theory] [WithFileCollection(nameof(CommonTestImages), DefaultPixelType, 1)] [WithFileCollection(nameof(CommonTestImages), DefaultPixelType, 4)] From 772cdda9780267e89d95e2a9d7ea504e1736745d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 29 Nov 2018 16:49:46 +0100 Subject: [PATCH 380/381] better comments + TolerantMath made readonly --- src/ImageSharp/Common/Helpers/TolerantMath.cs | 2 +- .../Transforms/Resize/ResizeKernelMap.cs | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/TolerantMath.cs b/src/ImageSharp/Common/Helpers/TolerantMath.cs index d95aea9de2..5347efcc09 100644 --- a/src/ImageSharp/Common/Helpers/TolerantMath.cs +++ b/src/ImageSharp/Common/Helpers/TolerantMath.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp /// Implements basic math operations using tolerant comparison /// whenever an equality check is needed. /// - internal struct TolerantMath + internal readonly struct TolerantMath { private readonly double epsilon; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index 347aaf0be0..f6edf97865 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -110,20 +110,33 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } int radius = (int)TolerantMath.Ceiling(scale * sampler.Radius); + + // 'ratio' is a rational number. + // Multiplying it by LCM(sourceSize, destSize)/sourceSize will result in a whole number "again". + // This value is determining the length of the periods in repeating kernel map rows. int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize; + + // the center position at i == 0: double center0 = (ratio - 1) * 0.5; double firstNonNegativeLeftVal = (radius - center0 - 1) / ratio; + + // The number of rows building a "stairway" at the top and the bottom of the kernel map + // corresponding to the corners of the image. + // If we do not normalize the kernel values, these rows also fit the periodic logic, + // however, it's just simpler to calculate them separately. int cornerInterval = (int)TolerantMath.Ceiling(firstNonNegativeLeftVal); - // corner case for cornerInteval: + // If firstNonNegativeLeftVal was an integral value, we don't need Ceiling: if (TolerantMath.AreEqual(firstNonNegativeLeftVal, cornerInterval)) { cornerInterval++; } - bool useMosaic = 2 * (cornerInterval + period) < destinationSize; + // If 'cornerInterval' is too big compared to 'period', we can't apply the periodic optimization. + // If we don't have at least 2 periods, we go with the basic implementation: + bool hasAtLeast2Periods = 2 * (cornerInterval + period) < destinationSize; - ResizeKernelMap result = useMosaic + ResizeKernelMap result = hasAtLeast2Periods ? new PeriodicKernelMap( memoryAllocator, sampler, From ab4cae48ace9d4f8d0586b49241164a43ad76a4f Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 29 Nov 2018 17:03:46 +0100 Subject: [PATCH 381/381] improve comments again --- .../Processors/Transforms/Resize/ResizeKernelMap.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index f6edf97865..2ab574df2a 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -104,9 +104,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms double ratio = (double)sourceSize / destinationSize; double scale = ratio; - if (scale < 1F) + if (scale < 1) { - scale = 1F; + scale = 1; } int radius = (int)TolerantMath.Ceiling(scale * sampler.Radius); @@ -126,7 +126,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // however, it's just simpler to calculate them separately. int cornerInterval = (int)TolerantMath.Ceiling(firstNonNegativeLeftVal); - // If firstNonNegativeLeftVal was an integral value, we don't need Ceiling: + // If firstNonNegativeLeftVal was an integral value, we need firstNonNegativeLeftVal+1 + // instead of Ceiling: if (TolerantMath.AreEqual(firstNonNegativeLeftVal, cornerInterval)) { cornerInterval++;