From 09b19832bca2241ad7a6ac6b321c680d509a3886 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 24 Aug 2016 00:57:48 +1000 Subject: [PATCH 1/3] Begin fitting packed vector with XNA etc Former-commit-id: 929527d603ef214c2975e64fb43b6f9867ab2a4a Former-commit-id: 476e47a8f3c03a02420b57fda0f7b0b70eab4bba Former-commit-id: 0a9e0b6e26bfc736835bcc4cb9f02a2da246fa59 --- src/ImageProcessorCore/Colors/Color.cs | 150 +++++++++++------- .../Colors/PackedVector/IPackedVector.cs | 30 ++-- .../Common/Extensions/ComparableExtensions.cs | 24 +++ src/ImageProcessorCore/Image/PixelAccessor.cs | 2 +- .../Quantizers/Octree/OctreeQuantizer.cs | 4 +- .../Image/GetSetPixel.cs | 4 +- 6 files changed, 141 insertions(+), 73 deletions(-) diff --git a/src/ImageProcessorCore/Colors/Color.cs b/src/ImageProcessorCore/Colors/Color.cs index d5570d6470..fc5c0a210d 100644 --- a/src/ImageProcessorCore/Colors/Color.cs +++ b/src/ImageProcessorCore/Colors/Color.cs @@ -8,7 +8,6 @@ namespace ImageProcessorCore using System; using System.Numerics; using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; /// /// Packed vector type containing four 8-bit unsigned normalized values ranging from 0 to 255. @@ -18,38 +17,77 @@ namespace ImageProcessorCore /// 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.Explicit)] public partial struct Color : IPackedVector, IEquatable { + private const float Max = 255F; + private const float Min = 0F; + private uint packedValue; + /// - /// Gets or sets the blue component. + /// Gets or sets the red component. /// - [FieldOffset(0)] - public byte R; + public byte R + { + get + { + return (byte)this.packedValue; + } + set + { + this.packedValue = (uint)(this.packedValue & -0x100 | value); + } + } + /// /// Gets or sets the green component. /// - [FieldOffset(1)] - public byte G; + public byte G + { + get + { + return (byte)(this.packedValue >> 8); + } + set + { + this.packedValue = (uint)(this.packedValue & -0xff01 | (uint)value << 8); + } + } /// - /// Gets or sets the red component. + /// Gets or sets the blue component. /// - [FieldOffset(2)] - public byte B; + public byte B + { + get + { + return (byte)(this.packedValue >> 16); + } + set + { + this.packedValue = (uint)(this.packedValue & -0xff0001 | (uint)(value << 16)); + } + } /// /// Gets or sets the alpha component. /// - [FieldOffset(3)] - public byte A; + public byte A + { + get + { + return (byte)(this.packedValue >> 24); + } + set + { + this.packedValue = this.packedValue & 0xffffff | (uint)value << 24; + } + } /// /// The packed value. /// - [FieldOffset(0)] - private uint packedValue; + public uint PackedValue { get { return this.packedValue; } set { this.packedValue = value; } } /// /// Initializes a new instance of the struct. @@ -61,10 +99,7 @@ namespace ImageProcessorCore public Color(byte r, byte g, byte b, byte a = 255) : this() { - this.R = r; - this.G = g; - this.B = b; - this.A = a; + this.packedValue = (uint)(r | g << 8 | b << 16 | a << 24); } /// @@ -87,17 +122,19 @@ namespace ImageProcessorCore if (hex.Length == 8) { - this.R = Convert.ToByte(hex.Substring(2, 2), 16); - this.G = Convert.ToByte(hex.Substring(4, 2), 16); - this.B = Convert.ToByte(hex.Substring(6, 2), 16); - this.A = Convert.ToByte(hex.Substring(0, 2), 16); + this.packedValue = + (uint)(Convert.ToByte(hex.Substring(2, 2), 16) + | Convert.ToByte(hex.Substring(4, 2), 16) << 8 + | Convert.ToByte(hex.Substring(6, 2), 16) << 16 + | Convert.ToByte(hex.Substring(0, 2), 16) << 24); } else if (hex.Length == 6) { - this.R = Convert.ToByte(hex.Substring(0, 2), 16); - this.G = Convert.ToByte(hex.Substring(2, 2), 16); - this.B = Convert.ToByte(hex.Substring(4, 2), 16); - this.A = 255; + this.packedValue = + (uint)(Convert.ToByte(hex.Substring(0, 2), 16) + | Convert.ToByte(hex.Substring(2, 2), 16) << 8 + | Convert.ToByte(hex.Substring(4, 2), 16) << 16 + | 255 << 24); } else { @@ -105,10 +142,11 @@ namespace ImageProcessorCore string gh = char.ToString(hex[1]); string bh = char.ToString(hex[2]); - this.R = Convert.ToByte(rh + rh, 16); - this.G = Convert.ToByte(gh + gh, 16); - this.B = Convert.ToByte(bh + bh, 16); - this.A = 255; + this.packedValue = + (uint)(Convert.ToByte(rh + rh, 16) + | Convert.ToByte(gh + gh, 16) << 8 + | Convert.ToByte(bh + bh, 16) << 16 + | 255 << 24); } } @@ -122,11 +160,7 @@ namespace ImageProcessorCore public Color(float r, float g, float b, float a = 1) : this() { - Vector4 clamped = Vector4.Clamp(new Vector4(r, g, b, a), Vector4.Zero, Vector4.One) * 255F; - this.R = (byte)Math.Round(clamped.X); - this.G = (byte)Math.Round(clamped.Y); - this.B = (byte)Math.Round(clamped.Z); - this.A = (byte)Math.Round(clamped.W); + Pack(ref r, ref g, ref b, ref a); } /// @@ -138,11 +172,8 @@ namespace ImageProcessorCore public Color(Vector3 vector) : this() { - Vector3 clamped = Vector3.Clamp(vector, Vector3.Zero, Vector3.One) * 255F; - this.R = (byte)Math.Round(clamped.X); - this.G = (byte)Math.Round(clamped.Y); - this.B = (byte)Math.Round(clamped.Z); - this.A = 255; + float a = 1; + Pack(ref vector.X, ref vector.Y, ref vector.Z, ref a); } /// @@ -154,11 +185,7 @@ namespace ImageProcessorCore public Color(Vector4 vector) : this() { - Vector4 clamped = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * 255F; - this.R = (byte)Math.Round(clamped.X); - this.G = (byte)Math.Round(clamped.Y); - this.B = (byte)Math.Round(clamped.Z); - this.A = (byte)Math.Round(clamped.W); + this.packedValue = Pack(ref vector); } /// @@ -206,20 +233,13 @@ namespace ImageProcessorCore /// public void PackFromVector4(Vector4 vector) { - Vector4 clamped = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * 255F; - this.R = (byte)Math.Round(clamped.X); - this.G = (byte)Math.Round(clamped.Y); - this.B = (byte)Math.Round(clamped.Z); - this.A = (byte)Math.Round(clamped.W); + this.packedValue = Pack(ref vector); } /// public void PackFromBytes(byte x, byte y, byte z, byte w) { - this.R = x; - this.G = y; - this.B = z; - this.A = w; + this.packedValue = (uint)(x | y << 8 | z << 16 | w << 24); } /// @@ -261,6 +281,28 @@ namespace ImageProcessorCore return this.GetHashCode(this); } + /// + /// Packs a vector into a uint. + /// + /// The vector containing the values to pack. + /// The ulong containing the packed values. + private static uint Pack(ref Vector4 vector) + { + // TODO: Maybe use Vector4.Clamp() instead. + return (uint)((byte)Math.Round(vector.X * Max).Clamp(Min, Max) + | ((byte)Math.Round(vector.Y * Max).Clamp(Min, Max) << 8) + | (byte)Math.Round(vector.Z * Max).Clamp(Min, Max) << 16 + | (byte)Math.Round(vector.W * Max).Clamp(Min, Max) << 24); + } + + private static uint Pack(ref float x, ref float y, ref float z, ref float w) + { + return (uint)((byte)Math.Round(x * Max).Clamp(Min, Max) + | ((byte)Math.Round(y * Max).Clamp(Min, Max) << 8) + | (byte)Math.Round(z * Max).Clamp(Min, Max) << 16 + | (byte)Math.Round(w * Max).Clamp(Min, Max) << 24); + } + /// /// Returns the hash code for this instance. /// diff --git a/src/ImageProcessorCore/Colors/PackedVector/IPackedVector.cs b/src/ImageProcessorCore/Colors/PackedVector/IPackedVector.cs index 114a173eb0..3ccf473f5c 100644 --- a/src/ImageProcessorCore/Colors/PackedVector/IPackedVector.cs +++ b/src/ImageProcessorCore/Colors/PackedVector/IPackedVector.cs @@ -15,21 +15,23 @@ namespace ImageProcessorCore public interface IPackedVector : IPackedVector where TPacked : struct { - /// - /// Directly gets the packed representation of the packed vector. - /// Typically packed in least to greatest significance order. - /// - /// - /// The . - /// - TPacked GetPackedValue(); + TPacked PackedValue { get; set; } - /// - /// Directly sets the packed representation of the packed vector. - /// Typically packed in least to greatest significance order. - /// - /// The packed value. - void SetPackedValue(TPacked value); + ///// + ///// Directly gets the packed representation of the packed vector. + ///// Typically packed in least to greatest significance order. + ///// + ///// + ///// The . + ///// + //TPacked GetPackedValue(); + + ///// + ///// Directly sets the packed representation of the packed vector. + ///// Typically packed in least to greatest significance order. + ///// + ///// The packed value. + //void SetPackedValue(TPacked value); } /// diff --git a/src/ImageProcessorCore/Common/Extensions/ComparableExtensions.cs b/src/ImageProcessorCore/Common/Extensions/ComparableExtensions.cs index cb0288fb7b..a2704ae65a 100644 --- a/src/ImageProcessorCore/Common/Extensions/ComparableExtensions.cs +++ b/src/ImageProcessorCore/Common/Extensions/ComparableExtensions.cs @@ -37,6 +37,30 @@ namespace ImageProcessorCore return value; } + /// + /// Restricts a to be within a specified range. + /// + /// The The value to clamp. + /// The minimum value. If value is less than min, min will be returned. + /// The maximum value. If value is greater than max, max will be returned. + /// + /// The representing the clamped value. + /// + public static uint Clamp(this uint value, uint min, uint max) + { + if (value > max) + { + return max; + } + + if (value < min) + { + return min; + } + + return value; + } + /// /// Restricts a to be within a specified range. /// diff --git a/src/ImageProcessorCore/Image/PixelAccessor.cs b/src/ImageProcessorCore/Image/PixelAccessor.cs index 833a4c6789..343b60dd14 100644 --- a/src/ImageProcessorCore/Image/PixelAccessor.cs +++ b/src/ImageProcessorCore/Image/PixelAccessor.cs @@ -10,7 +10,7 @@ namespace ImageProcessorCore using System.Runtime.InteropServices; /// - /// Encapsulates properties to provides per-pixel access to an images pixels. + /// Provides per-pixel access to generic pixels. /// /// The pixel format. /// The packed format. uint, long, float. diff --git a/src/ImageProcessorCore/Quantizers/Octree/OctreeQuantizer.cs b/src/ImageProcessorCore/Quantizers/Octree/OctreeQuantizer.cs index 522e07151b..42de023b03 100644 --- a/src/ImageProcessorCore/Quantizers/Octree/OctreeQuantizer.cs +++ b/src/ImageProcessorCore/Quantizers/Octree/OctreeQuantizer.cs @@ -193,11 +193,11 @@ namespace ImageProcessorCore.Quantizers /// Add a given color value to the Octree /// /// - /// The containing color information to add. + /// The containing color information to add. /// public void AddColor(TColor pixel) { - TPacked packed = pixel.GetPackedValue(); + TPacked packed = pixel.PackedValue; //.GetPackedValue(); // Check if this request is for the same color as the last if (this.previousColor.Equals(packed)) { diff --git a/tests/ImageProcessorCore.Benchmarks/Image/GetSetPixel.cs b/tests/ImageProcessorCore.Benchmarks/Image/GetSetPixel.cs index eb742404ef..09d8c862f9 100644 --- a/tests/ImageProcessorCore.Benchmarks/Image/GetSetPixel.cs +++ b/tests/ImageProcessorCore.Benchmarks/Image/GetSetPixel.cs @@ -10,7 +10,7 @@ public class GetSetPixel { - [Benchmark(Baseline = true, Description = "System.Drawing GetSeTColor pixel")] + [Benchmark(Baseline = true, Description = "System.Drawing GetSet pixel")] public SystemColor ResizeSystemDrawing() { using (Bitmap source = new Bitmap(400, 400)) @@ -20,7 +20,7 @@ } } - [Benchmark(Description = "ImageProcessorCore GetSeTColor pixel")] + [Benchmark(Description = "ImageProcessorCore GetSet pixel")] public CoreColor ResizeCore() { CoreImage image = new CoreImage(400, 400); From 693cf0df5ab0359c9360acc71d53aaf39e953bf8 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 24 Aug 2016 22:33:02 +1000 Subject: [PATCH 2/3] Remove bytes functions Former-commit-id: 153a5f985339b738d1cf15e10a3d42a6613ef729 Former-commit-id: ece59225c4bd1e6afad22fcf7a18d5cb60189228 Former-commit-id: 9d9fe57bb80e756284f496373c630b9ea09f3058 --- src/ImageProcessorCore/Colors/Color.cs | 41 +++++++++++------ .../Colors/PackedVector/IPackedVector.cs | 46 ++++++------------- .../Common/Helpers/ImageMaths.cs | 8 ++-- src/ImageProcessorCore/Filters/DetectEdges.cs | 2 +- .../ColorMatrix/LomographProcessor.cs | 2 +- .../ColorMatrix/PolaroidProcessor.cs | 4 +- .../Formats/Bmp/BmpDecoderCore.cs | 9 ++-- .../Formats/Bmp/BmpEncoderCore.cs | 10 ++-- .../Formats/Gif/GifDecoderCore.cs | 3 +- .../Formats/Gif/GifEncoderCore.cs | 8 ++-- .../Jpg/JpegDecoderCore.cs.REMOVED.git-id | 2 +- .../Formats/Jpg/JpegEncoderCore.cs | 8 ++-- .../Formats/Png/PngDecoderCore.cs | 14 +++--- .../Formats/Png/PngEncoderCore.cs | 20 ++++---- .../Quantizers/Octree/OctreeQuantizer.cs | 36 +++++++-------- .../Quantizers/Palette/PaletteQuantizer.cs | 20 ++++---- .../Quantizers/Wu/WuQuantizer.cs | 26 ++++++----- 17 files changed, 127 insertions(+), 132 deletions(-) diff --git a/src/ImageProcessorCore/Colors/Color.cs b/src/ImageProcessorCore/Colors/Color.cs index fc5c0a210d..3a21c21301 100644 --- a/src/ImageProcessorCore/Colors/Color.cs +++ b/src/ImageProcessorCore/Colors/Color.cs @@ -160,7 +160,7 @@ namespace ImageProcessorCore public Color(float r, float g, float b, float a = 1) : this() { - Pack(ref r, ref g, ref b, ref a); + this.packedValue = Pack(r, g, b, a); } /// @@ -172,8 +172,7 @@ namespace ImageProcessorCore public Color(Vector3 vector) : this() { - float a = 1; - Pack(ref vector.X, ref vector.Y, ref vector.Z, ref a); + this.packedValue = Pack(ref vector); } /// @@ -282,25 +281,39 @@ namespace ImageProcessorCore } /// - /// Packs a vector into a uint. + /// Packs a into a uint. /// /// The vector containing the values to pack. /// The ulong containing the packed values. private static uint Pack(ref Vector4 vector) { - // TODO: Maybe use Vector4.Clamp() instead. - return (uint)((byte)Math.Round(vector.X * Max).Clamp(Min, Max) - | ((byte)Math.Round(vector.Y * Max).Clamp(Min, Max) << 8) - | (byte)Math.Round(vector.Z * Max).Clamp(Min, Max) << 16 - | (byte)Math.Round(vector.W * Max).Clamp(Min, Max) << 24); + return Pack(vector.X, vector.Y, vector.Z, vector.W); + } + + /// + /// Packs a into a uint. + /// + /// The vector containing the values to pack. + /// The ulong containing the packed values. + private static uint Pack(ref Vector3 vector) + { + return Pack(vector.X, vector.Y, vector.Z, 1); } - private static uint Pack(ref float x, ref float y, ref float z, ref float w) + /// + /// Packs the four floats into a uint. + /// + /// The x-component + /// The y-component + /// The z-component + /// The w-component + /// The + private static uint Pack(float x, float y, float z, float w) { - return (uint)((byte)Math.Round(x * Max).Clamp(Min, Max) - | ((byte)Math.Round(y * Max).Clamp(Min, Max) << 8) - | (byte)Math.Round(z * Max).Clamp(Min, Max) << 16 - | (byte)Math.Round(w * Max).Clamp(Min, Max) << 24); + return (uint)((byte)Math.Round(x.Clamp(0, 1) * Max) + | ((byte)Math.Round(y.Clamp(0, 1) * Max) << 8) + | (byte)Math.Round(z.Clamp(0, 1) * Max) << 16 + | (byte)Math.Round(w.Clamp(0, 1) * Max) << 24); } /// diff --git a/src/ImageProcessorCore/Colors/PackedVector/IPackedVector.cs b/src/ImageProcessorCore/Colors/PackedVector/IPackedVector.cs index 3ccf473f5c..a0d71e4e20 100644 --- a/src/ImageProcessorCore/Colors/PackedVector/IPackedVector.cs +++ b/src/ImageProcessorCore/Colors/PackedVector/IPackedVector.cs @@ -16,22 +16,6 @@ namespace ImageProcessorCore where TPacked : struct { TPacked PackedValue { get; set; } - - ///// - ///// Directly gets the packed representation of the packed vector. - ///// Typically packed in least to greatest significance order. - ///// - ///// - ///// The . - ///// - //TPacked GetPackedValue(); - - ///// - ///// Directly sets the packed representation of the packed vector. - ///// Typically packed in least to greatest significance order. - ///// - ///// The packed value. - //void SetPackedValue(TPacked value); } /// @@ -45,14 +29,14 @@ namespace ImageProcessorCore /// The vector to create the packed representation from. void PackFromVector4(Vector4 vector); - /// - /// Sets the packed representation from a . - /// - /// The x-component to create the packed representation from. - /// The y-component to create the packed representation from. - /// The z-component to create the packed representation from. - /// The w-component to create the packed representation from. - void PackFromBytes(byte x, byte y, byte z, byte w); + ///// + ///// Sets the packed representation from a . + ///// + ///// The x-component to create the packed representation from. + ///// The y-component to create the packed representation from. + ///// The z-component to create the packed representation from. + ///// The w-component to create the packed representation from. + //void PackFromBytes(byte x, byte y, byte z, byte w); /// /// Expands the packed representation into a . @@ -61,12 +45,12 @@ namespace ImageProcessorCore /// The . Vector4 ToVector4(); - /// - /// Expands the packed representation into a . - /// The bytes are typically expanded in least to greatest significance order. - /// Red -> Green -> Blue -> Alpha - /// - /// The . - byte[] ToBytes(); + ///// + ///// Expands the packed representation into a . + ///// The bytes are typically expanded in least to greatest significance order. + ///// Red -> Green -> Blue -> Alpha + ///// + ///// The . + //byte[] ToBytes(); } } diff --git a/src/ImageProcessorCore/Common/Helpers/ImageMaths.cs b/src/ImageProcessorCore/Common/Helpers/ImageMaths.cs index f356841395..19da0af187 100644 --- a/src/ImageProcessorCore/Common/Helpers/ImageMaths.cs +++ b/src/ImageProcessorCore/Common/Helpers/ImageMaths.cs @@ -180,19 +180,19 @@ namespace ImageProcessorCore switch (channel) { case RgbaComponent.R: - delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToBytes()[0] - b) > Epsilon; + delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().X - b) > Epsilon; break; case RgbaComponent.G: - delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToBytes()[1] - b) > Epsilon; + delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().Y - b) > Epsilon; break; case RgbaComponent.B: - delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToBytes()[2] - b) > Epsilon; + delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().Z - b) > Epsilon; break; default: - delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToBytes()[3] - b) > Epsilon; + delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().W - b) > Epsilon; break; } diff --git a/src/ImageProcessorCore/Filters/DetectEdges.cs b/src/ImageProcessorCore/Filters/DetectEdges.cs index 9e906fcf77..d306badbb8 100644 --- a/src/ImageProcessorCore/Filters/DetectEdges.cs +++ b/src/ImageProcessorCore/Filters/DetectEdges.cs @@ -118,7 +118,7 @@ namespace ImageProcessorCore break; default: - processor = new ScharrProcessor { Grayscale = grayscale }; + processor = new SobelProcessor { Grayscale = grayscale }; break; } diff --git a/src/ImageProcessorCore/Filters/Processors/ColorMatrix/LomographProcessor.cs b/src/ImageProcessorCore/Filters/Processors/ColorMatrix/LomographProcessor.cs index 10de7109cd..ba2cee9648 100644 --- a/src/ImageProcessorCore/Filters/Processors/ColorMatrix/LomographProcessor.cs +++ b/src/ImageProcessorCore/Filters/Processors/ColorMatrix/LomographProcessor.cs @@ -31,7 +31,7 @@ namespace ImageProcessorCore.Processors protected override void AfterApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) { TColor packed = default(TColor); - packed.PackFromBytes(0, 10, 0, 255); // Very dark (mostly black) lime green. + packed.PackFromVector4(new Color(0, 10, 0).ToVector4()); // Very dark (mostly black) lime green. new VignetteProcessor { VignetteColor = packed }.Apply(target, target, sourceRectangle); } } diff --git a/src/ImageProcessorCore/Filters/Processors/ColorMatrix/PolaroidProcessor.cs b/src/ImageProcessorCore/Filters/Processors/ColorMatrix/PolaroidProcessor.cs index 956896c649..b288386374 100644 --- a/src/ImageProcessorCore/Filters/Processors/ColorMatrix/PolaroidProcessor.cs +++ b/src/ImageProcessorCore/Filters/Processors/ColorMatrix/PolaroidProcessor.cs @@ -37,11 +37,11 @@ namespace ImageProcessorCore.Processors protected override void AfterApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) { TColor packedV = default(TColor); - packedV.PackFromBytes(102, 34, 0, 255); // Very dark orange [Brown tone] + packedV.PackFromVector4(new Color(102, 34, 0).ToVector4()); // Very dark orange [Brown tone] new VignetteProcessor { VignetteColor = packedV }.Apply(target, target, sourceRectangle); TColor packedG = default(TColor); - packedG.PackFromBytes(255, 153, 102, 178); // Light orange + packedG.PackFromVector4(new Color(255, 153, 102, 178).ToVector4()); // Light orange new GlowProcessor { GlowColor = packedG, Radius = target.Width / 4F }.Apply(target, target, sourceRectangle); } } diff --git a/src/ImageProcessorCore/Formats/Bmp/BmpDecoderCore.cs b/src/ImageProcessorCore/Formats/Bmp/BmpDecoderCore.cs index 82d7823f4e..cd3e0e56e8 100644 --- a/src/ImageProcessorCore/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageProcessorCore/Formats/Bmp/BmpDecoderCore.cs @@ -243,7 +243,7 @@ namespace ImageProcessorCore.Formats // Stored in b-> g-> r order. TColor packed = default(TColor); - packed.PackFromBytes(colors[colorIndex + 2], colors[colorIndex + 1], colors[colorIndex], 255); + packed.PackFromVector4(new Color(colors[colorIndex + 2], colors[colorIndex + 1], colors[colorIndex]).ToVector4()); imageData[arrayOffset] = packed; } } @@ -295,7 +295,7 @@ namespace ImageProcessorCore.Formats // Stored in b-> g-> r order. TColor packed = default(TColor); - packed.PackFromBytes(r, g, b, 255); + packed.PackFromVector4(new Color(r, g, b).ToVector4()); imageData[arrayOffset] = packed; } }); @@ -333,10 +333,9 @@ namespace ImageProcessorCore.Formats int offset = rowOffset + (x * 3); int arrayOffset = ((row * width) + x); - // We divide by 255 as we will store the colors in our floating point format. // Stored in b-> g-> r-> a order. TColor packed = default(TColor); - packed.PackFromBytes(data[offset + 2], data[offset + 1], data[offset], 255); + packed.PackFromVector4(new Color(data[offset + 2], data[offset + 1], data[offset]).ToVector4()); imageData[arrayOffset] = packed; } }); @@ -376,7 +375,7 @@ namespace ImageProcessorCore.Formats // Stored in b-> g-> r-> a order. TColor packed = default(TColor); - packed.PackFromBytes(data[offset + 2], data[offset + 1], data[offset], data[offset + 3]); + packed.PackFromVector4(new Color(data[offset + 2], data[offset + 1], data[offset], data[offset + 3]).ToVector4()); imageData[arrayOffset] = packed; } }); diff --git a/src/ImageProcessorCore/Formats/Bmp/BmpEncoderCore.cs b/src/ImageProcessorCore/Formats/Bmp/BmpEncoderCore.cs index 5b959d8442..441ffc4a34 100644 --- a/src/ImageProcessorCore/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageProcessorCore/Formats/Bmp/BmpEncoderCore.cs @@ -160,8 +160,8 @@ namespace ImageProcessorCore.Formats for (int x = 0; x < pixels.Width; x++) { // Convert back to b-> g-> r-> a order. - byte[] bytes = pixels[x, y].ToBytes(); - writer.Write(new[] { bytes[2], bytes[1], bytes[0], bytes[3] }); + Color color = new Color(pixels[x, y].ToVector4()); + writer.Write(new[] { color.B, color.G, color.R, color.A }); } // Pad @@ -177,7 +177,7 @@ namespace ImageProcessorCore.Formats /// /// The pixel format. /// The packed format. uint, long, float./// The containing the stream to write to. - /// The containing pixel data. + /// The containing pixel data. private void Write24Bit(EndianBinaryWriter writer, PixelAccessor pixels) where TColor : IPackedVector where TPacked : struct @@ -187,8 +187,8 @@ namespace ImageProcessorCore.Formats for (int x = 0; x < pixels.Width; x++) { // Convert back to b-> g-> r order. - byte[] bytes = pixels[x, y].ToBytes(); - writer.Write(new[] { bytes[2], bytes[1], bytes[0] }); + Color color = new Color(pixels[x, y].ToVector4()); + writer.Write(new[] { color.B, color.G, color.R }); } // Pad diff --git a/src/ImageProcessorCore/Formats/Gif/GifDecoderCore.cs b/src/ImageProcessorCore/Formats/Gif/GifDecoderCore.cs index d37bca929a..fbd421ccf0 100644 --- a/src/ImageProcessorCore/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageProcessorCore/Formats/Gif/GifDecoderCore.cs @@ -358,9 +358,8 @@ namespace ImageProcessorCore.Formats { // Stored in r-> g-> b-> a order. int indexOffset = index * 3; - TColor pixel = default(TColor); - pixel.PackFromBytes(colorTable[indexOffset], colorTable[indexOffset + 1], colorTable[indexOffset + 2], 255); + pixel.PackFromVector4(new Color(colorTable[indexOffset], colorTable[indexOffset + 1], colorTable[indexOffset + 2]).ToVector4()); this.currentFrame[offset] = pixel; } diff --git a/src/ImageProcessorCore/Formats/Gif/GifEncoderCore.cs b/src/ImageProcessorCore/Formats/Gif/GifEncoderCore.cs index cf4d39a89c..b73a5bab59 100644 --- a/src/ImageProcessorCore/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageProcessorCore/Formats/Gif/GifEncoderCore.cs @@ -281,11 +281,11 @@ namespace ImageProcessorCore.Formats i => { int offset = i * 3; - byte[] color = palette[i].ToBytes(); + Color color = new Color(palette[i].ToVector4()); - colorTable[offset] = color[0]; - colorTable[offset + 1] = color[1]; - colorTable[offset + 2] = color[2]; + colorTable[offset] = color.R; + colorTable[offset + 1] = color.G; + colorTable[offset + 2] = color.B; }); writer.Write(colorTable, 0, colorTableLength); diff --git a/src/ImageProcessorCore/Formats/Jpg/JpegDecoderCore.cs.REMOVED.git-id b/src/ImageProcessorCore/Formats/Jpg/JpegDecoderCore.cs.REMOVED.git-id index bd65b87026..45afa1afc7 100644 --- a/src/ImageProcessorCore/Formats/Jpg/JpegDecoderCore.cs.REMOVED.git-id +++ b/src/ImageProcessorCore/Formats/Jpg/JpegDecoderCore.cs.REMOVED.git-id @@ -1 +1 @@ -d6ce5dd6236ac6ef9ba570fb4e57e81c06bbb854 \ No newline at end of file +508fcf1910c42f4e080fcfd9c9f22ba724c1990c \ No newline at end of file diff --git a/src/ImageProcessorCore/Formats/Jpg/JpegEncoderCore.cs b/src/ImageProcessorCore/Formats/Jpg/JpegEncoderCore.cs index 783406a28c..baab490cf4 100644 --- a/src/ImageProcessorCore/Formats/Jpg/JpegEncoderCore.cs +++ b/src/ImageProcessorCore/Formats/Jpg/JpegEncoderCore.cs @@ -2,6 +2,9 @@ // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // + +using System.Numerics; + namespace ImageProcessorCore.Formats { using System; @@ -349,10 +352,7 @@ namespace ImageProcessorCore.Formats { for (int i = 0; i < 8; i++) { - // Bytes are expected in r->g->b->a oder. - byte[] pixel = pixels[Math.Min(x + i, xmax), Math.Min(y + j, ymax)].ToBytes(); - - YCbCr color = new Color(pixel[0], pixel[1], pixel[2], pixel[3]); + YCbCr color = new Color(pixels[Math.Min(x + i, xmax), Math.Min(y + j, ymax)].ToVector4()); int index = (8 * j) + i; yBlock[index] = (int)color.Y; cbBlock[index] = (int)color.Cb; diff --git a/src/ImageProcessorCore/Formats/Png/PngDecoderCore.cs b/src/ImageProcessorCore/Formats/Png/PngDecoderCore.cs index 3cf8be40eb..f9cc691cb8 100644 --- a/src/ImageProcessorCore/Formats/Png/PngDecoderCore.cs +++ b/src/ImageProcessorCore/Formats/Png/PngDecoderCore.cs @@ -3,6 +3,8 @@ // Licensed under the Apache License, Version 2.0. // +using System.Numerics; + namespace ImageProcessorCore.Formats { using System; @@ -339,7 +341,7 @@ namespace ImageProcessorCore.Formats byte intensity = defilteredScanline[offset]; TColor color = default(TColor); - color.PackFromBytes(intensity, intensity, intensity, 255); + color.PackFromVector4(new Vector4(intensity, intensity, intensity, 255) / 255F); pixels[(row * this.header.Width) + x] = color; } @@ -355,7 +357,7 @@ namespace ImageProcessorCore.Formats byte alpha = defilteredScanline[offset + bytesPerSample]; TColor color = default(TColor); - color.PackFromBytes(intensity, intensity, intensity, alpha); + color.PackFromVector4(new Vector4(intensity, intensity, intensity, alpha) / 255F); pixels[(row * this.header.Width) + x] = color; } @@ -382,7 +384,7 @@ namespace ImageProcessorCore.Formats byte r = this.palette[pixelOffset]; byte g = this.palette[pixelOffset + 1]; byte b = this.palette[pixelOffset + 2]; - color.PackFromBytes(r, g, b, a); + color.PackFromVector4(new Vector4(r, g, b, a) / 255F); } pixels[offset] = color; @@ -401,7 +403,7 @@ namespace ImageProcessorCore.Formats byte b = this.palette[pixelOffset + 2]; TColor color = default(TColor); - color.PackFromBytes(r, g, b, 255); + color.PackFromVector4(new Vector4(r, g, b, 255) / 255F); pixels[offset] = color; } } @@ -419,7 +421,7 @@ namespace ImageProcessorCore.Formats byte b = defilteredScanline[offset + 2 * bytesPerSample]; TColor color = default(TColor); - color.PackFromBytes(r, g, b, 255); + color.PackFromVector4(new Vector4(r, g, b, 255) / 255F); pixels[(row * this.header.Width) + x] = color; } @@ -437,7 +439,7 @@ namespace ImageProcessorCore.Formats byte a = defilteredScanline[offset + 3 * bytesPerSample]; TColor color = default(TColor); - color.PackFromBytes(r, g, b, a); + color.PackFromVector4(new Vector4(r, g, b, a) / 255F); pixels[(row * this.header.Width) + x] = color; } diff --git a/src/ImageProcessorCore/Formats/Png/PngEncoderCore.cs b/src/ImageProcessorCore/Formats/Png/PngEncoderCore.cs index f666f0f0ee..0613c26ad9 100644 --- a/src/ImageProcessorCore/Formats/Png/PngEncoderCore.cs +++ b/src/ImageProcessorCore/Formats/Png/PngEncoderCore.cs @@ -264,15 +264,17 @@ namespace ImageProcessorCore.Formats Bootstrapper.Instance.ParallelOptions, y => { - // Color data is stored in r -> g -> b -> a order for (int x = 0; x < this.width; x++) { int dataOffset = (y * stride) + (x * this.bytesPerPixel); - byte[] source = pixels[x, y].ToBytes(); + Color source = new Color(pixels[x, y].ToVector4()); - for (int i = 0; i < this.bytesPerPixel; i++) + this.pixelData[dataOffset] = source.R; + this.pixelData[dataOffset + 1] = source.G; + this.pixelData[dataOffset + 2] = source.B; + if (this.bytesPerPixel == 4) { - this.pixelData[dataOffset + i] = source[i]; + this.pixelData[dataOffset + 3] = source.A; } } }); @@ -511,12 +513,10 @@ namespace ImageProcessorCore.Formats i => { int offset = i * 3; - byte[] color = palette[i].ToBytes(); - - // Expected format r->g->b - colorTable[offset] = color[0]; - colorTable[offset + 1] = color[1]; - colorTable[offset + 2] = color[2]; + Color color = new Color(palette[i].ToVector4()); + colorTable[offset] = color.R; + colorTable[offset + 1] = color.G; + colorTable[offset + 2] = color.B; }); this.WriteChunk(stream, PngChunkTypes.Palette, colorTable); diff --git a/src/ImageProcessorCore/Quantizers/Octree/OctreeQuantizer.cs b/src/ImageProcessorCore/Quantizers/Octree/OctreeQuantizer.cs index 42de023b03..ac5c142f9b 100644 --- a/src/ImageProcessorCore/Quantizers/Octree/OctreeQuantizer.cs +++ b/src/ImageProcessorCore/Quantizers/Octree/OctreeQuantizer.cs @@ -86,7 +86,7 @@ namespace ImageProcessorCore.Quantizers byte paletteIndex = (byte)this.colors; // Get the palette index if it's transparency meets criterea. - if (pixel.ToBytes()[3] > this.Threshold) + if (new Color(pixel.ToVector4()).A > this.Threshold) { paletteIndex = (byte)this.octree.GetPaletteIndex(pixel); } @@ -397,10 +397,10 @@ namespace ImageProcessorCore.Quantizers { // Go to the next level down in the tree int shift = 7 - level; - byte[] components = pixel.ToBytes(); - int index = ((components[2] & Mask[level]) >> (shift - 2)) | - ((components[1] & Mask[level]) >> (shift - 1)) | - ((components[0] & Mask[level]) >> shift); + Color color = new Color(pixel.ToVector4()); + int index = ((color.B & Mask[level]) >> (shift - 2)) | + ((color.G & Mask[level]) >> (shift - 1)) | + ((color.R & Mask[level]) >> shift); OctreeNode child = this.children[index]; @@ -468,7 +468,7 @@ namespace ImageProcessorCore.Quantizers // And set the color of the palette entry TColor pixel = default(TColor); - pixel.PackFromBytes(r, g, b, 255); + pixel.PackFromVector4(new Color(r, g, b).ToVector4()); palette.Add(pixel); } else @@ -487,12 +487,8 @@ namespace ImageProcessorCore.Quantizers /// /// Return the palette index for the passed color /// - /// - /// The representing the pixel. - /// - /// - /// The level. - /// + /// The representing the pixel. + /// The level. /// /// The representing the index of the pixel in the palette. /// @@ -503,10 +499,10 @@ namespace ImageProcessorCore.Quantizers if (!this.leaf) { int shift = 7 - level; - byte[] components = pixel.ToBytes(); - int pixelIndex = ((components[2] & Mask[level]) >> (shift - 2)) | - ((components[1] & Mask[level]) >> (shift - 1)) | - ((components[0] & Mask[level]) >> shift); + Color color = new Color(pixel.ToVector4()); + int pixelIndex = ((color.B & Mask[level]) >> (shift - 2)) | + ((color.G & Mask[level]) >> (shift - 1)) | + ((color.R & Mask[level]) >> shift); if (this.children[pixelIndex] != null) { @@ -530,10 +526,10 @@ namespace ImageProcessorCore.Quantizers public void Increment(TColor pixel) { this.pixelCount++; - byte[] components = pixel.ToBytes(); - this.red += components[0]; - this.green += components[1]; - this.blue += components[2]; + Color color = new Color(pixel.ToVector4()); + this.red += color.R; + this.green += color.G; + this.blue += color.B; } } } diff --git a/src/ImageProcessorCore/Quantizers/Palette/PaletteQuantizer.cs b/src/ImageProcessorCore/Quantizers/Palette/PaletteQuantizer.cs index a075705358..0a3f12ba8d 100644 --- a/src/ImageProcessorCore/Quantizers/Palette/PaletteQuantizer.cs +++ b/src/ImageProcessorCore/Quantizers/Palette/PaletteQuantizer.cs @@ -81,13 +81,13 @@ namespace ImageProcessorCore.Quantizers { // Not found - loop through the palette and find the nearest match. // Firstly check the alpha value - if less than the threshold, lookup the transparent color - byte[] bytes = pixel.ToBytes(); - if (!(bytes[3] > this.Threshold)) + Color color =new Color(pixel.ToVector4()); + if (!(color.A > this.Threshold)) { // Transparent. Lookup the first color with an alpha value of 0 for (int index = 0; index < this.colors.Length; index++) { - if (this.colors[index].ToBytes()[3] == 0) + if (new Color(this.colors[index].ToVector4()).A == 0) { colorIndex = (byte)index; this.TransparentIndex = colorIndex; @@ -99,17 +99,17 @@ namespace ImageProcessorCore.Quantizers { // Not transparent... int leastDistance = int.MaxValue; - int red = bytes[0]; - int green = bytes[1]; - int blue = bytes[2]; + int red = color.R; + int green = color.G; + int blue = color.B; // Loop through the entire palette, looking for the closest color match for (int index = 0; index < this.colors.Length; index++) { - byte[] paletteColor = this.colors[index].ToBytes(); - int redDistance = paletteColor[0] - red; - int greenDistance = paletteColor[1] - green; - int blueDistance = paletteColor[2] - blue; + Color paletteColor = new Color(this.colors[index].ToVector4()); + int redDistance = paletteColor.R - red; + int greenDistance = paletteColor.G - green; + int blueDistance = paletteColor.B - blue; int distance = (redDistance * redDistance) + (greenDistance * greenDistance) + diff --git a/src/ImageProcessorCore/Quantizers/Wu/WuQuantizer.cs b/src/ImageProcessorCore/Quantizers/Wu/WuQuantizer.cs index a1f6b8f3cb..2ee802a5dc 100644 --- a/src/ImageProcessorCore/Quantizers/Wu/WuQuantizer.cs +++ b/src/ImageProcessorCore/Quantizers/Wu/WuQuantizer.cs @@ -3,6 +3,8 @@ // Licensed under the Apache License, Version 2.0. // +using System.Numerics; + namespace ImageProcessorCore.Quantizers { using System; @@ -332,12 +334,12 @@ namespace ImageProcessorCore.Quantizers for (int x = 0; x < pixels.Width; x++) { // Colors are expected in r->g->b->a format - byte[] color = pixels[x, y].ToBytes(); + Color color = new Color(pixels[x, y].ToVector4()); - byte r = color[0]; - byte g = color[1]; - byte b = color[2]; - byte a = color[3]; + byte r = color.R; + byte g = color.G; + byte b = color.B; + byte a = color.A; int inr = r >> (8 - IndexBits); int ing = g >> (8 - IndexBits); @@ -745,7 +747,7 @@ namespace ImageProcessorCore.Quantizers byte a = (byte)(Volume(cube[k], this.vma) / weight); TColor color = default(TColor); - color.PackFromBytes(r, g, b, a); + color.PackFromVector4(new Vector4(r, g, b, a) / 255F); if (color.Equals(default(TColor))) { @@ -770,13 +772,13 @@ namespace ImageProcessorCore.Quantizers for (int x = 0; x < width; x++) { // Expected order r->g->b->a - byte[] color = imagePixels[x, y].ToBytes(); - int r = color[0] >> (8 - IndexBits); - int g = color[1] >> (8 - IndexBits); - int b = color[2] >> (8 - IndexBits); - int a = color[3] >> (8 - IndexAlphaBits); + Color color = new Color(imagePixels[x, y].ToVector4()); + int r = color.R >> (8 - IndexBits); + int g = color.G >> (8 - IndexBits); + int b = color.B >> (8 - IndexBits); + int a = color.A >> (8 - IndexAlphaBits); - if (transparentIndex > -1 && color[3] <= this.Threshold) + if (transparentIndex > -1 && color.A <= this.Threshold) { pixels[(y * width) + x] = (byte)transparentIndex; continue; From ff4b388b4be9f94e57cffdbb48dc9ebb677a3314 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 29 Aug 2016 12:08:19 +1000 Subject: [PATCH 3/3] Fix broken test Former-commit-id: fe1ad3d4658ad1f0fba85b2d5542647f7402d916 Former-commit-id: ec449be911a1e233e622aac48a1309cfa4e82a50 Former-commit-id: ed1eef3c2745a106a4f508d2632127d2216fa783 --- tests/ImageProcessorCore.Tests/Colors/ColorTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageProcessorCore.Tests/Colors/ColorTests.cs b/tests/ImageProcessorCore.Tests/Colors/ColorTests.cs index 69ed6ff73d..82e1bd80e5 100644 --- a/tests/ImageProcessorCore.Tests/Colors/ColorTests.cs +++ b/tests/ImageProcessorCore.Tests/Colors/ColorTests.cs @@ -96,7 +96,7 @@ namespace ImageProcessorCore.Tests { const string First = "FF000000"; Color color = Color.Black; - string second = color.GetPackedValue().ToString("X"); + string second = color.PackedValue.ToString("X"); Assert.Equal(First, second); } }