diff --git a/src/ImageSharp/Colors/PackedPixel/Byte4.cs b/src/ImageSharp/Colors/PackedPixel/Byte4.cs index 9b4be5711..f757ac077 100644 --- a/src/ImageSharp/Colors/PackedPixel/Byte4.cs +++ b/src/ImageSharp/Colors/PackedPixel/Byte4.cs @@ -91,13 +91,13 @@ namespace ImageSharp /// public void PackFromBytes(byte x, byte y, byte z, byte w) { - this.PackFromVector4(new Vector4(x, y, z, w) / 255F); + this.PackFromVector4(new Vector4(x, y, z, w)); } /// public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) { - Vector4 vector = this.ToVector4() * 255F; + Vector4 vector = this.ToVector4(); switch (componentOrder) { @@ -174,4 +174,4 @@ namespace ImageSharp return byte4 | byte3 | byte2 | byte1; } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Colors/PackedPixel/HalfVector4.cs b/src/ImageSharp/Colors/PackedPixel/HalfVector4.cs index 4c4da339b..635155f0c 100644 --- a/src/ImageSharp/Colors/PackedPixel/HalfVector4.cs +++ b/src/ImageSharp/Colors/PackedPixel/HalfVector4.cs @@ -32,8 +32,8 @@ namespace ImageSharp /// The w-component. public HalfVector4(float x, float y, float z, float w) { - var vector = new Vector4(x, y, z, w); - this.PackedValue = PackHelper(ref vector); + Vector4 vector = new Vector4(x, y, z, w); + this.PackedValue = Pack(ref vector); } /// @@ -42,7 +42,7 @@ namespace ImageSharp /// A vector containing the initial values for the components public HalfVector4(Vector4 vector) { - this.PackedValue = PackHelper(ref vector); + this.PackedValue = Pack(ref vector); } /// @@ -85,7 +85,7 @@ namespace ImageSharp /// public void PackFromVector4(Vector4 vector) { - this.PackedValue = PackHelper(ref vector); + this.PackedValue = Pack(ref vector); } /// @@ -170,7 +170,7 @@ namespace ImageSharp /// /// The vector containing the values to pack. /// The containing the packed values. - private static ulong PackHelper(ref Vector4 vector) + private static ulong Pack(ref Vector4 vector) { ulong num4 = HalfTypeHelper.Pack(vector.X); ulong num3 = (ulong)HalfTypeHelper.Pack(vector.Y) << 0x10; diff --git a/src/ImageSharp/Colors/PackedPixel/PackedPixelConverterHelper.cs b/src/ImageSharp/Colors/PackedPixel/PackedPixelConverterHelper.cs index 84f89a33b..f356024b3 100644 --- a/src/ImageSharp/Colors/PackedPixel/PackedPixelConverterHelper.cs +++ b/src/ImageSharp/Colors/PackedPixel/PackedPixelConverterHelper.cs @@ -36,19 +36,16 @@ namespace ImageSharp Type source = typeof(TColor); Type target = typeof(TColor2); - // Standard to offset + // Normalized standard if (IsStandardNormalizedType(source)) { - if (IsOffsetNormalizedType(target) || IsOffsetTwoComponentNormalizedType(target)) - { - // Expand the range then offset the center down. - return vector4 => (2F * vector4) - Vector4.One; - } + return FromStandardNormalizedType(target); + } - if (IsOffsetType(target) || IsOffsetTwoComponentType(target)) - { - return v => (65534 * v) - new Vector4(32767); - } + // Standard + if (IsStandardType(source)) + { + return FromStandardType(target); } // Normalized offsets. All four components. @@ -78,6 +75,61 @@ namespace ImageSharp return Noop; } + /// + /// Returns the correct conversion function to convert from types having vector values representing all four components + /// ranging from 0 to 1. + /// + /// The target type + /// The + private static Func FromStandardNormalizedType(Type target) + { + if (IsStandardType(target)) + { + return vector4 => 255F * vector4; + } + + if (IsOffsetNormalizedType(target) || IsOffsetTwoComponentNormalizedType(target)) + { + // Expand the range then offset the center down. + return vector4 => (2F * vector4) - Vector4.One; + } + + if (IsOffsetType(target) || IsOffsetTwoComponentType(target)) + { + return vector4 => (65534F * vector4) - new Vector4(32767F); + } + + return Noop; + } + + /// + /// Returns the correct conversion function to convert from types having vector values representing all four components + /// ranging from 0 to 255. + /// + /// The target type + /// The + private static Func FromStandardType(Type target) + { + // Scale down + if (IsStandardNormalizedType(target)) + { + return vector4 => vector4 / 255F; + } + + if (IsOffsetNormalizedType(target) || IsOffsetTwoComponentNormalizedType(target)) + { + // Expand the range, divide, then offset the center down. + return vector4 => ((2F * (vector4 / 255F)) - Vector4.One); + } + + if (IsOffsetType(target) || IsOffsetTwoComponentType(target)) + { + return vector4 => (65534F * (vector4 / 255F)) - new Vector4(32767F); + } + + return Noop; + } + /// /// Returns the correct conversion function to convert from types having vector values representing all four components /// ranging from -1 to 1. @@ -92,6 +144,12 @@ namespace ImageSharp return vector4 => (vector4 / 2F) + new Vector4(.5F); } + if (IsStandardType(target)) + { + // Compress the range, multiply, then offset the center up. + return vector4 => ((vector4 / 2F) * 255F) + new Vector4(127.5F); + } + if (IsOffsetType(target) || IsOffsetTwoComponentType(target)) { // Multiply out the range, two component won't read the last two values. @@ -112,13 +170,19 @@ namespace ImageSharp if (IsStandardNormalizedType(target)) { // Compress the range then offset the center up. - return vector4 => (vector4 / 65534) + new Vector4(.5F); + return vector4 => (vector4 / 65534F) + new Vector4(.5F); + } + + if (IsStandardType(target)) + { + // Compress the range, multiply, then offset the center up. + return vector4 => ((vector4 / 65534F) * 255F) + new Vector4(127.5F); } if (IsOffsetNormalizedType(target) || IsOffsetTwoComponentNormalizedType(target)) { // Compress the range. Two component won't read the last two values. - return vector4 => (vector4 / 32767); + return vector4 => (vector4 / 32767F); } return Noop; @@ -138,20 +202,30 @@ namespace ImageSharp { // Compress the range then offset the center up for first pair. Vector4 v = (vector4 / 2F) + new Vector4(.5F); - return new Vector4(v.X, v.Y, 0, 1); + return new Vector4(v.X, v.Y, 0F, 1F); + }; + } + + if (IsStandardType(target)) + { + return vector4 => + { + // Compress the range, multiply, then offset the center up for first pair. + Vector4 v = ((vector4 / 2F) * 255F) + new Vector4(127.5F); + return new Vector4(v.X, v.Y, 0F, 255F); }; } if (IsOffsetNormalizedType(target)) { // Copy the first two components and set second pair to 0 and 1 equivalent. - return vector4 => new Vector4(vector4.X, vector4.Y, -1, 1); + return vector4 => new Vector4(vector4.X, vector4.Y, -1F, 1F); } if (IsOffsetTwoComponentType(target)) { // Multiply. Two component won't read the last two values. - return vector4 => (vector4 * 32767); + return vector4 => (vector4 * 32767F); } if (IsOffsetType(target)) @@ -159,8 +233,8 @@ namespace ImageSharp return vector4 => { // Multiply the first two components and set second pair to 0 and 1 equivalent. - Vector4 v = vector4 * 32767; - return new Vector4(v.X, v.Y, -32767, 32767); + Vector4 v = vector4 * 32767F; + return new Vector4(v.X, v.Y, -32767F, 32767F); }; } @@ -179,15 +253,24 @@ namespace ImageSharp { return vector4 => { - Vector4 v = (vector4 / 65534) + new Vector4(.5F); + Vector4 v = (vector4 / 65534F) + new Vector4(.5F); return new Vector4(v.X, v.Y, 0, 1); }; } + if (IsStandardType(target)) + { + return vector4 => + { + Vector4 v = ((vector4 / 65534F) * 255F) + new Vector4(127.5F); + return new Vector4(v.X, v.Y, 0, 255F); + }; + } + if (IsOffsetType(target)) { // Copy the first two components and set second pair to 0 and 1 equivalent. - return vector4 => new Vector4(vector4.X, vector4.Y, -32767, 32767); + return vector4 => new Vector4(vector4.X, vector4.Y, -32767F, 32767F); } if (IsOffsetNormalizedType(target)) @@ -195,15 +278,15 @@ namespace ImageSharp return vector4 => { // Divide the first two components and set second pair to 0 and 1 equivalent. - Vector4 v = vector4 / 32767; - return new Vector4(v.X, v.Y, -1, 1); + Vector4 v = vector4 / 32767F; + return new Vector4(v.X, v.Y, -1F, 1F); }; } if (IsOffsetTwoComponentNormalizedType(target)) { // Divide. Two component won't read the last two values. - return vector4 => (vector4 / 32767); + return vector4 => (vector4 / 32767F); } return Noop; @@ -217,10 +300,10 @@ namespace ImageSharp private static bool IsStandardNormalizedType(Type type) { return type == typeof(Color) + || type == typeof(Alpha8) || type == typeof(Bgr565) || type == typeof(Bgra4444) || type == typeof(Bgra5551) - || type == typeof(Byte4) || type == typeof(HalfSingle) || type == typeof(HalfVector2) || type == typeof(HalfVector4) @@ -229,6 +312,16 @@ namespace ImageSharp || type == typeof(Rgba64); } + /// + /// Identifies the type as having vector component values ranging from 0 to 255. + /// + /// The type to test. + /// The + private static bool IsStandardType(Type type) + { + return type == typeof(Byte4); + } + /// /// Identifies the type as having vector values representing the first component pair ranging from -1 to 1. /// and the second component pair ranging from 0 to 1. diff --git a/tests/ImageSharp.Tests/Colors/PackedPixelTests.cs b/tests/ImageSharp.Tests/Colors/PackedPixelTests.cs index 785125ca1..583191bfc 100644 --- a/tests/ImageSharp.Tests/Colors/PackedPixelTests.cs +++ b/tests/ImageSharp.Tests/Colors/PackedPixelTests.cs @@ -249,6 +249,11 @@ namespace ImageSharp.Tests.Colors new Byte4(x, y, z, w).ToBytes(bgra, 0, ComponentOrder.ZYXW); Assert.Equal(bgra, new byte[] { 0, 0, 128, 0 }); + + Byte4 r = new Byte4(); + r.PackFromBytes(20, 38, 0, 255); + r.ToBytes(rgba, 0, ComponentOrder.XYZW); + Assert.Equal(rgba, new byte[] { 20, 38, 0, 255 }); } [Fact] diff --git a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs index 575fcf091..850801e0e 100644 --- a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs +++ b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs @@ -54,6 +54,23 @@ namespace ImageSharp.Tests { Image image = file.CreateImage(); + //var image = file.CreateImage() + // .To() + // .To() + // .To() + // .To() + // .To() + // .To() + // .To() + // .To() + // .To() + // .To() + // .To() + // .To() + // .To() + // .To() + // .To(); + // Image image = file.CreateImage().To(); // Image image = file.CreateImage().To(); // Image image = file.CreateImage().To();