From e9ddf0f604bc071dfa7a2eb3539d0745d2f59248 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 12 Jun 2018 22:28:38 +1000 Subject: [PATCH 01/30] Refactor Rgba64 --- src/ImageSharp/PixelFormats/Rgba64.cs | 124 +++++++++++++----- .../PixelFormats/Rgba64Tests.cs | 7 + 2 files changed, 96 insertions(+), 35 deletions(-) diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/Rgba64.cs index 5d1aa0067..b2442bfea 100644 --- a/src/ImageSharp/PixelFormats/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/Rgba64.cs @@ -4,6 +4,7 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.PixelFormats { @@ -13,18 +14,61 @@ namespace SixLabors.ImageSharp.PixelFormats /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. /// /// + [StructLayout(LayoutKind.Sequential)] public struct Rgba64 : IPixel, IPackedVector { + private const float Max = 65535F; + + /// + /// Gets or sets the red component. + /// + public ushort R; + + /// + /// Gets or sets the green component. + /// + public ushort G; + + /// + /// Gets or sets the blue component. + /// + public ushort B; + + /// + /// Gets or sets the alpha component. + /// + public ushort A; + + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The alpha component. + public Rgba64(ushort r, ushort g, ushort b, ushort a) + : this() + { + this.R = r; + this.G = g; + this.B = b; + this.A = a; + } + /// /// Initializes a new instance of the struct. /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - public Rgba64(float x, float y, float z, float w) + /// The red component. + /// The green component. + /// The blue component. + /// The alpha component. + public Rgba64(float r, float g, float b, float a) + : this() { - this.PackedValue = Pack(x, y, z, w); + 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); } /// @@ -32,12 +76,39 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// 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.Rgba = packed; + } + + /// + /// Gets or sets the packed representation of the struct. + /// + public ulong Rgba { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Unsafe.As(ref this); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => Unsafe.As(ref this) = value; } /// - public ulong PackedValue { get; set; } + public ulong PackedValue + { + get => this.Rgba; + set => this.Rgba = value; + } /// /// Compares two objects for equality. @@ -54,7 +125,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Rgba64 left, Rgba64 right) { - return left.PackedValue == right.PackedValue; + return left.Rgba == right.Rgba; } /// @@ -72,7 +143,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Rgba64 left, Rgba64 right) { - return left.PackedValue != right.PackedValue; + return left.Rgba != right.Rgba; } /// @@ -96,18 +167,18 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 ToVector4() { - return new Vector4( - (this.PackedValue & 0xFFFF) / 65535F, - ((this.PackedValue >> 16) & 0xFFFF) / 65535F, - ((this.PackedValue >> 32) & 0xFFFF) / 65535F, - ((this.PackedValue >> 48) & 0xFFFF) / 65535F); + return new Vector4(this.R / Max, this.G / Max, this.B / Max, this.A / Max); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromVector4(Vector4 vector) { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; + this.R = (ushort)MathF.Round(vector.X); + this.G = (ushort)MathF.Round(vector.Y); + this.B = (ushort)MathF.Round(vector.Z); + this.A = (ushort)MathF.Round(vector.W); } /// @@ -194,7 +265,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Rgba64 other) { - return this.PackedValue == other.PackedValue; + return this.Rgba == other.Rgba; } /// @@ -209,22 +280,5 @@ namespace SixLabors.ImageSharp.PixelFormats { return 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 ulong Pack(float x, float y, float z, float w) - { - return (ulong)MathF.Round(x.Clamp(0, 1) * 65535F) | - ((ulong)MathF.Round(y.Clamp(0, 1) * 65535F) << 16) | - ((ulong)MathF.Round(z.Clamp(0, 1) * 65535F) << 32) | - ((ulong)MathF.Round(w.Clamp(0, 1) * 65535F) << 48); - } } -} +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index ffe512855..d8d6bcf8b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -12,7 +12,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] 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); From 45345370bb284d092e3716a257db8ee21498d7a1 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 12 Jun 2018 23:43:42 +1000 Subject: [PATCH 02/30] Add Rgba64 methods to IPixel. Touch #610 TODO: Tests --- src/ImageSharp/PixelFormats/Alpha8.cs | 8 ++++++++ src/ImageSharp/PixelFormats/Argb32.cs | 8 ++++++++ src/ImageSharp/PixelFormats/Bgr24.cs | 8 ++++++++ src/ImageSharp/PixelFormats/Bgr565.cs | 8 ++++++++ src/ImageSharp/PixelFormats/Bgra32.cs | 11 ++++++++++- src/ImageSharp/PixelFormats/Bgra4444.cs | 8 ++++++++ src/ImageSharp/PixelFormats/Bgra5551.cs | 8 ++++++++ src/ImageSharp/PixelFormats/Byte4.cs | 8 ++++++++ src/ImageSharp/PixelFormats/HalfSingle.cs | 8 ++++++++ src/ImageSharp/PixelFormats/HalfVector2.cs | 8 ++++++++ src/ImageSharp/PixelFormats/HalfVector4.cs | 8 ++++++++ src/ImageSharp/PixelFormats/IPixel.cs | 12 ++++++++++++ src/ImageSharp/PixelFormats/NormalizedByte2.cs | 8 ++++++++ src/ImageSharp/PixelFormats/NormalizedByte4.cs | 8 ++++++++ src/ImageSharp/PixelFormats/NormalizedShort2.cs | 8 ++++++++ src/ImageSharp/PixelFormats/NormalizedShort4.cs | 8 ++++++++ src/ImageSharp/PixelFormats/Rg32.cs | 8 ++++++++ src/ImageSharp/PixelFormats/Rgb24.cs | 8 ++++++++ src/ImageSharp/PixelFormats/Rgba1010102.cs | 8 ++++++++ src/ImageSharp/PixelFormats/Rgba32.cs | 8 ++++++++ src/ImageSharp/PixelFormats/Rgba64.cs | 14 ++++++++++++++ src/ImageSharp/PixelFormats/RgbaVector.cs | 8 ++++++++ src/ImageSharp/PixelFormats/Short2.cs | 8 ++++++++ src/ImageSharp/PixelFormats/Short4.cs | 8 ++++++++ 24 files changed, 204 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/Alpha8.cs index 659b2439f..8c5d06584 100644 --- a/src/ImageSharp/PixelFormats/Alpha8.cs +++ b/src/ImageSharp/PixelFormats/Alpha8.cs @@ -155,6 +155,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = this.PackedValue; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + /// /// Compares an object with the packed vector. /// diff --git a/src/ImageSharp/PixelFormats/Argb32.cs b/src/ImageSharp/PixelFormats/Argb32.cs index ef869af01..7773395e7 100644 --- a/src/ImageSharp/PixelFormats/Argb32.cs +++ b/src/ImageSharp/PixelFormats/Argb32.cs @@ -310,6 +310,14 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public Argb32 ToArgb32() => this; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + /// public override bool Equals(object obj) { diff --git a/src/ImageSharp/PixelFormats/Bgr24.cs b/src/ImageSharp/PixelFormats/Bgr24.cs index b099bab1c..5430e3b22 100644 --- a/src/ImageSharp/PixelFormats/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/Bgr24.cs @@ -176,5 +176,13 @@ namespace SixLabors.ImageSharp.PixelFormats dest.B = this.B; dest.A = 255; } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Bgr565.cs b/src/ImageSharp/PixelFormats/Bgr565.cs index d1fa162e7..dd50b28dc 100644 --- a/src/ImageSharp/PixelFormats/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/Bgr565.cs @@ -187,6 +187,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)MathF.Round(vector.W); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + /// public override bool Equals(object obj) { diff --git a/src/ImageSharp/PixelFormats/Bgra32.cs b/src/ImageSharp/PixelFormats/Bgra32.cs index de660c05b..733966137 100644 --- a/src/ImageSharp/PixelFormats/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/Bgra32.cs @@ -252,12 +252,21 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public Bgra32 ToBgra32() => this; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + /// /// Packs a into a color. /// /// The vector containing the values to pack. [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void Pack(ref Vector4 vector) { + private void Pack(ref Vector4 vector) + { vector *= MaxBytes; vector += Half; vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); diff --git a/src/ImageSharp/PixelFormats/Bgra4444.cs b/src/ImageSharp/PixelFormats/Bgra4444.cs index 393723c85..70a63dccd 100644 --- a/src/ImageSharp/PixelFormats/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/Bgra4444.cs @@ -178,6 +178,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + /// public override bool Equals(object obj) { diff --git a/src/ImageSharp/PixelFormats/Bgra5551.cs b/src/ImageSharp/PixelFormats/Bgra5551.cs index ba3441270..5c8c3f17e 100644 --- a/src/ImageSharp/PixelFormats/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/Bgra5551.cs @@ -178,6 +178,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + /// public override bool Equals(object obj) { diff --git a/src/ImageSharp/PixelFormats/Byte4.cs b/src/ImageSharp/PixelFormats/Byte4.cs index d91dac9ac..96c564773 100644 --- a/src/ImageSharp/PixelFormats/Byte4.cs +++ b/src/ImageSharp/PixelFormats/Byte4.cs @@ -179,6 +179,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + /// public override bool Equals(object obj) { diff --git a/src/ImageSharp/PixelFormats/HalfSingle.cs b/src/ImageSharp/PixelFormats/HalfSingle.cs index f85370ba1..ffd3bce18 100644 --- a/src/ImageSharp/PixelFormats/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/HalfSingle.cs @@ -192,6 +192,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + /// public override bool Equals(object obj) { diff --git a/src/ImageSharp/PixelFormats/HalfVector2.cs b/src/ImageSharp/PixelFormats/HalfVector2.cs index acee34d6c..ec609ae62 100644 --- a/src/ImageSharp/PixelFormats/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/HalfVector2.cs @@ -207,6 +207,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + /// public override string ToString() { diff --git a/src/ImageSharp/PixelFormats/HalfVector4.cs b/src/ImageSharp/PixelFormats/HalfVector4.cs index 7c4cfb31c..4d0579cc1 100644 --- a/src/ImageSharp/PixelFormats/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/HalfVector4.cs @@ -200,6 +200,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + /// public override string ToString() { diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index 7501cf382..5bb9b1a7f 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -61,6 +61,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// The value. void PackFromRgba32(Rgba32 source); + /// + /// Packs the pixel from an value. + /// + /// The value. + void PackFromRgba64(Rgba64 source); + /// /// Packs the pixel from an value. /// @@ -85,6 +91,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// The destination pixel to write to void ToRgba32(ref Rgba32 dest); + /// + /// Converts the pixel to format. + /// + /// The destination pixel to write to + void ToRgba64(ref Rgba64 dest); + /// /// Converts the pixel to format. /// diff --git a/src/ImageSharp/PixelFormats/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/NormalizedByte2.cs index 36ca11dd8..ef69a7da8 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte2.cs @@ -226,6 +226,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + /// public override bool Equals(object obj) { diff --git a/src/ImageSharp/PixelFormats/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/NormalizedByte4.cs index 8471285c7..7c0b54258 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte4.cs @@ -219,6 +219,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + /// public override bool Equals(object obj) { diff --git a/src/ImageSharp/PixelFormats/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/NormalizedShort2.cs index 6907594a0..8bc9511fa 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort2.cs @@ -213,6 +213,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. diff --git a/src/ImageSharp/PixelFormats/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/NormalizedShort4.cs index 78c65212b..a7941e59e 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort4.cs @@ -221,6 +221,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)MathF.Round(vector.W); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + /// public override bool Equals(object obj) { diff --git a/src/ImageSharp/PixelFormats/Rg32.cs b/src/ImageSharp/PixelFormats/Rg32.cs index 696b823ce..ec1d7e069 100644 --- a/src/ImageSharp/PixelFormats/Rg32.cs +++ b/src/ImageSharp/PixelFormats/Rg32.cs @@ -191,6 +191,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + /// public override bool Equals(object obj) { diff --git a/src/ImageSharp/PixelFormats/Rgb24.cs b/src/ImageSharp/PixelFormats/Rgb24.cs index c540a7d12..d5341e14b 100644 --- a/src/ImageSharp/PixelFormats/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/Rgb24.cs @@ -174,6 +174,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + /// public override string ToString() { diff --git a/src/ImageSharp/PixelFormats/Rgba1010102.cs b/src/ImageSharp/PixelFormats/Rgba1010102.cs index 166936d5e..550348736 100644 --- a/src/ImageSharp/PixelFormats/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/Rgba1010102.cs @@ -185,6 +185,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)MathF.Round(vector.W); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + /// public override bool Equals(object obj) { diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index f6979aad8..a61e2e7a2 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -384,6 +384,14 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32 ToRgba32() => this; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + /// public override bool Equals(object obj) { diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/Rgba64.cs index b2442bfea..a20a76c84 100644 --- a/src/ImageSharp/PixelFormats/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/Rgba64.cs @@ -202,6 +202,13 @@ namespace SixLabors.ImageSharp.PixelFormats this.PackFromVector4(source.ToVector4()); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) + { + this = source; + } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ToRgb24(ref Rgb24 dest) @@ -223,6 +230,13 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)MathF.Round(vector.W); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) + { + dest = this; + } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ToArgb32(ref Argb32 dest) diff --git a/src/ImageSharp/PixelFormats/RgbaVector.cs b/src/ImageSharp/PixelFormats/RgbaVector.cs index 6eaf69214..8d49ba4d9 100644 --- a/src/ImageSharp/PixelFormats/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/RgbaVector.cs @@ -298,6 +298,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)MathF.Round(vector.W); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromScaledVector4(Vector4 vector) diff --git a/src/ImageSharp/PixelFormats/Short2.cs b/src/ImageSharp/PixelFormats/Short2.cs index abe653e88..dcc7e00b5 100644 --- a/src/ImageSharp/PixelFormats/Short2.cs +++ b/src/ImageSharp/PixelFormats/Short2.cs @@ -207,6 +207,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. diff --git a/src/ImageSharp/PixelFormats/Short4.cs b/src/ImageSharp/PixelFormats/Short4.cs index d3bb891d9..1f73e4a38 100644 --- a/src/ImageSharp/PixelFormats/Short4.cs +++ b/src/ImageSharp/PixelFormats/Short4.cs @@ -213,6 +213,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)MathF.Round(vector.W); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + /// public override bool Equals(object obj) { From e349d4ba8c039008da04306fe64e8ce8c63d5c51 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 14 Jun 2018 00:36:02 +1000 Subject: [PATCH 03/30] Read Rgba64 png + some tests --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 37 +++++----- .../PixelOperations{TPixel}.Generated.cs | 71 +++++++++++++++++++ .../PixelOperations{TPixel}.Generated.tt | 45 ++++++++++++ .../PixelFormats/Alpha8Tests.cs | 33 +++++++++ .../PixelFormats/Argb32Tests.cs | 16 +++++ .../PixelFormats/Bgr24Tests.cs | 20 +++++- .../PixelFormats/Bgr565Tests.cs | 18 ++++- .../PixelFormats/Bgra32Tests.cs | 18 ++++- .../PixelFormats/Bgra4444Tests.cs | 16 +++++ 9 files changed, 249 insertions(+), 25 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index cc98b8450..c122aa404 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -784,12 +784,15 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.header.BitDepth == 16) { - int length = this.header.Width * 4; - using (IBuffer compressed = this.configuration.MemoryManager.Allocate(length)) + Rgba64 rgba64 = default; + for (int x = 0, o = 0; x < this.header.Width; x++, o += 8) { - // TODO: Should we use pack from vector here instead? - this.From16BitTo8Bit(scanlineBuffer, compressed.Span, length); - PixelOperations.Instance.PackFromRgba32Bytes(compressed.Span, rowSpan, this.header.Width); + rgba64.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2)); + rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2)); + rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 4, 2)); + rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 6, 2)); + color.PackFromRgba64(rgba64); + rowSpan[x] = color; } } else @@ -1053,23 +1056,15 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.header.BitDepth == 16) { - int length = this.header.Width * 4; - using (IBuffer compressed = this.configuration.MemoryManager.Allocate(length)) + Rgba64 rgba64 = default; + for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 8) { - Span compressedSpan = compressed.Span; - - // TODO: Should we use pack from vector here instead? - this.From16BitTo8Bit(scanlineBuffer, compressedSpan, length); - for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 4) - { - rgba.R = compressedSpan[o]; - rgba.G = compressedSpan[o + 1]; - rgba.B = compressedSpan[o + 2]; - rgba.A = compressedSpan[o + 3]; - - color.PackFromRgba32(rgba); - rowSpan[x] = color; - } + rgba64.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2)); + rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2)); + rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 4, 2)); + rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 6, 2)); + color.PackFromRgba64(rgba64); + rowSpan[x] = color; } } else diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs index 025204c89..2656f9a3a 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs @@ -11,6 +11,77 @@ 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. + /// The to the destination pixels. + /// The number of pixels to convert. + internal virtual void PackFromRgba64(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); + + var rgba = new Rgba64(0, 0, 0, 65535); + + 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); + } + } + + /// + /// 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) + { + 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. + /// The number of pixels to convert. + internal virtual void ToRgba64(ReadOnlySpan sourcePixels, Span dest, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + + ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destBaseRef = ref MemoryMarshal.GetReference(dest); + + 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); + sp.ToRgba64(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 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. /// diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt index 060973c74..f73f37eb8 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt @@ -51,6 +51,48 @@ <# } + 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 GeneratePackFromMethodUsingPackFromRgba32(string pixelType, string rgbaOperationCode) { #> @@ -192,6 +234,9 @@ namespace SixLabors.ImageSharp.PixelFormats { <# + GeneratePackFromMethodUsingPackFromRgba64("Rgba64", "rgba = Unsafe.Add(ref sourceRef, i);"); + GenerateToDestFormatMethods("Rgba64"); + GeneratePackFromMethodUsingPackFromRgba32("Rgba32", "rgba = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Rgba32"); diff --git a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs index 56d6043a6..39da9f538 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs @@ -157,5 +157,38 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // 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_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 f432aca8a..79b803be8 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs @@ -189,5 +189,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // 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 33cdadb66..bac668ebd 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs @@ -22,13 +22,13 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(g, p.G); Assert.Equal(b, p.B); } - + [Fact] public unsafe void ByteLayoutIsSequentialBgr() { var color = new Bgr24(1, 2, 3); byte* ptr = (byte*)&color; - + Assert.Equal(3, ptr[0]); Assert.Equal(2, ptr[1]); Assert.Equal(1, ptr[2]); @@ -139,5 +139,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); } + + [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 b1640c33d..39f221832 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs @@ -6,7 +6,7 @@ using SixLabors.ImageSharp.PixelFormats; using Xunit; namespace SixLabors.ImageSharp.Tests.PixelFormats -{ +{ public class Bgr565Tests { [Fact] @@ -144,5 +144,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // 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 71e04269d..701268f5d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public static readonly TheoryData ColorData = new TheoryData() { - { 1, 2, 3, 4 }, { 4, 5, 6, 7 }, { 0, 255, 42, 0 }, { 1, 2, 3, 255 } + { 1, 2, 3, 4 }, { 4, 5, 6, 7 }, { 0, 255, 42, 0 }, { 1, 2, 3, 255 } }; [Theory] @@ -146,5 +146,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(new Bgra32(1, 2, 3, 4), bgra); } + + [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 07667220f..0bb3b2919 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs @@ -193,5 +193,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // 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); + } } } From 88cb24266e35f4124145b93d7800dfe06bdf4130 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 14 Jun 2018 00:50:22 +1000 Subject: [PATCH 04/30] Add some TODOs --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 8a2ece4be..819fa4d70 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetBitsNeededForColorDepth(int colors) { - return (int)Math.Ceiling(Math.Log(colors, 2)); + return Math.Min(1, (int)Math.Ceiling(Math.Log(colors, 2))); } /// diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index f17c9009a..ce9eb6008 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -197,6 +197,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { + // TODO: How do we set this in the options while keeping the value inline with the PngColorType? this.bitDepth = 8; } @@ -209,7 +210,7 @@ namespace SixLabors.ImageSharp.Formats.Png bitDepth: this.bitDepth, filterMethod: 0, // None compressionMethod: 0, - interlaceMethod: 0); + interlaceMethod: 0); // TODO: Can't write interlaced yet. this.WriteHeaderChunk(stream, header); @@ -281,6 +282,7 @@ namespace SixLabors.ImageSharp.Formats.Png private void CollectTPixelBytes(ReadOnlySpan rowSpan) where TPixel : struct, IPixel { + // TODO: We need to cater for 64bit mode here. if (this.bytesPerPixel == 4) { PixelOperations.Instance.ToRgba32Bytes(rowSpan, this.rawScanline.Span, this.width); @@ -400,6 +402,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The private int CalculateBytesPerPixel() { + // TODO: Cater for 64 bit here and below switch (this.pngColorType) { case PngColorType.Grayscale: From 7c72ea51dc075285c4033138b601514a7cc23604 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 14 Jun 2018 11:22:04 +1000 Subject: [PATCH 05/30] Fix ImageMaths change. --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 819fa4d70..641b7f390 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetBitsNeededForColorDepth(int colors) { - return Math.Min(1, (int)Math.Ceiling(Math.Log(colors, 2))); + return Math.Max(1, (int)Math.Ceiling(Math.Log(colors, 2))); } /// From fa4226a21b4fc31aa0cb1fb6abd57cda2f8184ac Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 14 Jun 2018 16:02:29 +1000 Subject: [PATCH 06/30] Fix conversion add conversion tests --- src/ImageSharp/PixelFormats/Alpha8.cs | 4 ++-- src/ImageSharp/PixelFormats/Argb32.cs | 4 ++-- src/ImageSharp/PixelFormats/Bgr24.cs | 4 ++-- src/ImageSharp/PixelFormats/Bgr565.cs | 4 ++-- src/ImageSharp/PixelFormats/Bgra32.cs | 4 ++-- src/ImageSharp/PixelFormats/Bgra4444.cs | 4 ++-- src/ImageSharp/PixelFormats/Bgra5551.cs | 4 ++-- src/ImageSharp/PixelFormats/Byte4.cs | 4 ++-- src/ImageSharp/PixelFormats/HalfSingle.cs | 4 ++-- src/ImageSharp/PixelFormats/HalfVector2.cs | 4 ++-- src/ImageSharp/PixelFormats/HalfVector4.cs | 4 ++-- src/ImageSharp/PixelFormats/NormalizedByte2.cs | 4 ++-- src/ImageSharp/PixelFormats/NormalizedByte4.cs | 4 ++-- .../PixelFormats/NormalizedShort2.cs | 4 ++-- .../PixelFormats/NormalizedShort4.cs | 4 ++-- src/ImageSharp/PixelFormats/Rg32.cs | 4 ++-- src/ImageSharp/PixelFormats/Rgb24.cs | 4 ++-- src/ImageSharp/PixelFormats/Rgba1010102.cs | 4 ++-- src/ImageSharp/PixelFormats/Rgba32.cs | 4 ++-- src/ImageSharp/PixelFormats/RgbaVector.cs | 4 ++-- src/ImageSharp/PixelFormats/Short2.cs | 4 ++-- src/ImageSharp/PixelFormats/Short4.cs | 4 ++-- .../PixelFormats/Bgra5551Tests.cs | 16 ++++++++++++++++ .../PixelFormats/Byte4Tests.cs | 16 ++++++++++++++++ .../PixelFormats/HalfSingleTests.cs | 16 ++++++++++++++++ .../PixelFormats/HalfVector2Tests.cs | 16 ++++++++++++++++ .../PixelFormats/HalfVector4Tests.cs | 16 ++++++++++++++++ .../PixelFormats/NormalizedByte2Tests.cs | 16 ++++++++++++++++ .../PixelFormats/NormalizedByte4Tests.cs | 16 ++++++++++++++++ .../PixelFormats/NormalizedShort2Tests.cs | 16 ++++++++++++++++ .../PixelFormats/NormalizedShort4Tests.cs | 16 ++++++++++++++++ .../ImageSharp.Tests/PixelFormats/Rg32Tests.cs | 16 ++++++++++++++++ .../PixelFormats/Rgb24Tests.cs | 18 +++++++++++++++++- .../PixelFormats/Rgba1010102Tests.cs | 16 ++++++++++++++++ .../PixelFormats/Rgba32Tests.cs | 16 ++++++++++++++++ .../PixelFormats/Rgba64Tests.cs | 16 ++++++++++++++++ .../PixelFormats/RgbaVectorTests.cs | 18 +++++++++++++++++- .../PixelFormats/Short2Tests.cs | 16 ++++++++++++++++ .../PixelFormats/Short4Tests.cs | 16 ++++++++++++++++ 39 files changed, 318 insertions(+), 46 deletions(-) diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/Alpha8.cs index 8c5d06584..0328e8bb3 100644 --- a/src/ImageSharp/PixelFormats/Alpha8.cs +++ b/src/ImageSharp/PixelFormats/Alpha8.cs @@ -157,11 +157,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// /// Compares an object with the packed vector. diff --git a/src/ImageSharp/PixelFormats/Argb32.cs b/src/ImageSharp/PixelFormats/Argb32.cs index 7773395e7..ca16be93b 100644 --- a/src/ImageSharp/PixelFormats/Argb32.cs +++ b/src/ImageSharp/PixelFormats/Argb32.cs @@ -312,11 +312,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// public override bool Equals(object obj) diff --git a/src/ImageSharp/PixelFormats/Bgr24.cs b/src/ImageSharp/PixelFormats/Bgr24.cs index 5430e3b22..01df05552 100644 --- a/src/ImageSharp/PixelFormats/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/Bgr24.cs @@ -179,10 +179,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Bgr565.cs b/src/ImageSharp/PixelFormats/Bgr565.cs index dd50b28dc..755590bfe 100644 --- a/src/ImageSharp/PixelFormats/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/Bgr565.cs @@ -189,11 +189,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// public override bool Equals(object obj) diff --git a/src/ImageSharp/PixelFormats/Bgra32.cs b/src/ImageSharp/PixelFormats/Bgra32.cs index 733966137..e51948996 100644 --- a/src/ImageSharp/PixelFormats/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/Bgra32.cs @@ -254,11 +254,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// /// Packs a into a color. diff --git a/src/ImageSharp/PixelFormats/Bgra4444.cs b/src/ImageSharp/PixelFormats/Bgra4444.cs index 70a63dccd..75717ec8b 100644 --- a/src/ImageSharp/PixelFormats/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/Bgra4444.cs @@ -180,11 +180,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// public override bool Equals(object obj) diff --git a/src/ImageSharp/PixelFormats/Bgra5551.cs b/src/ImageSharp/PixelFormats/Bgra5551.cs index 5c8c3f17e..8f673d1dc 100644 --- a/src/ImageSharp/PixelFormats/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/Bgra5551.cs @@ -180,11 +180,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// public override bool Equals(object obj) diff --git a/src/ImageSharp/PixelFormats/Byte4.cs b/src/ImageSharp/PixelFormats/Byte4.cs index 96c564773..bc662cef9 100644 --- a/src/ImageSharp/PixelFormats/Byte4.cs +++ b/src/ImageSharp/PixelFormats/Byte4.cs @@ -181,11 +181,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// public override bool Equals(object obj) diff --git a/src/ImageSharp/PixelFormats/HalfSingle.cs b/src/ImageSharp/PixelFormats/HalfSingle.cs index ffd3bce18..7f0dff07a 100644 --- a/src/ImageSharp/PixelFormats/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/HalfSingle.cs @@ -194,11 +194,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// public override bool Equals(object obj) diff --git a/src/ImageSharp/PixelFormats/HalfVector2.cs b/src/ImageSharp/PixelFormats/HalfVector2.cs index ec609ae62..0f4b06a0f 100644 --- a/src/ImageSharp/PixelFormats/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/HalfVector2.cs @@ -209,11 +209,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// public override string ToString() diff --git a/src/ImageSharp/PixelFormats/HalfVector4.cs b/src/ImageSharp/PixelFormats/HalfVector4.cs index 4d0579cc1..745f48a91 100644 --- a/src/ImageSharp/PixelFormats/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/HalfVector4.cs @@ -202,11 +202,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// public override string ToString() diff --git a/src/ImageSharp/PixelFormats/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/NormalizedByte2.cs index ef69a7da8..306894b11 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte2.cs @@ -228,11 +228,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// public override bool Equals(object obj) diff --git a/src/ImageSharp/PixelFormats/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/NormalizedByte4.cs index 7c0b54258..620f3191d 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte4.cs @@ -221,11 +221,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// public override bool Equals(object obj) diff --git a/src/ImageSharp/PixelFormats/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/NormalizedShort2.cs index 8bc9511fa..38df71523 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort2.cs @@ -215,11 +215,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// /// Expands the packed representation into a . diff --git a/src/ImageSharp/PixelFormats/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/NormalizedShort4.cs index a7941e59e..dc6587900 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort4.cs @@ -223,11 +223,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// public override bool Equals(object obj) diff --git a/src/ImageSharp/PixelFormats/Rg32.cs b/src/ImageSharp/PixelFormats/Rg32.cs index ec1d7e069..0efacd0dd 100644 --- a/src/ImageSharp/PixelFormats/Rg32.cs +++ b/src/ImageSharp/PixelFormats/Rg32.cs @@ -193,11 +193,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// public override bool Equals(object obj) diff --git a/src/ImageSharp/PixelFormats/Rgb24.cs b/src/ImageSharp/PixelFormats/Rgb24.cs index d5341e14b..c3b870dff 100644 --- a/src/ImageSharp/PixelFormats/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/Rgb24.cs @@ -176,11 +176,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// public override string ToString() diff --git a/src/ImageSharp/PixelFormats/Rgba1010102.cs b/src/ImageSharp/PixelFormats/Rgba1010102.cs index 550348736..adaec7051 100644 --- a/src/ImageSharp/PixelFormats/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/Rgba1010102.cs @@ -187,11 +187,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// public override bool Equals(object obj) diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index a61e2e7a2..83ba6664f 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -386,11 +386,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 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 8d49ba4d9..637a5f362 100644 --- a/src/ImageSharp/PixelFormats/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/RgbaVector.cs @@ -300,11 +300,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/Short2.cs b/src/ImageSharp/PixelFormats/Short2.cs index dcc7e00b5..593132d2b 100644 --- a/src/ImageSharp/PixelFormats/Short2.cs +++ b/src/ImageSharp/PixelFormats/Short2.cs @@ -209,11 +209,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// /// Expands the packed representation into a . diff --git a/src/ImageSharp/PixelFormats/Short4.cs b/src/ImageSharp/PixelFormats/Short4.cs index 1f73e4a38..3daabe9ba 100644 --- a/src/ImageSharp/PixelFormats/Short4.cs +++ b/src/ImageSharp/PixelFormats/Short4.cs @@ -215,11 +215,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// public override bool Equals(object obj) diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs index b44651196..6ca822ed1 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs @@ -192,5 +192,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // 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 b6c623216..8e9ef4b3e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs @@ -190,5 +190,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // 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 5507243dd..ed853e6b8 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs @@ -141,5 +141,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // 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 fe806e0c9..0cdf493d6 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs @@ -146,5 +146,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // 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 5744243a4..1d6b7195b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs @@ -188,5 +188,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // 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 418e89ecc..d727fd952 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs @@ -157,5 +157,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // 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 1a31b806b..09b5b3e57 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs @@ -168,5 +168,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // 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 fc952a55c..5a9d5a36e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs @@ -161,5 +161,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // 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 ead301c56..55e4b7d98 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs @@ -169,5 +169,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // 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 cbecda8d5..cc7969846 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs @@ -128,5 +128,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // 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 5ba21096e..f86081404 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.False(a.Equals(b)); Assert.False(a.Equals((object)b)); } - + [Fact] public void PackFromRgba32() { @@ -139,5 +139,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); } + + [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/Rgba1010102Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs index 361dd67b5..9c28547dd 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs @@ -178,5 +178,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // 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 b8645d83c..c41f075ef 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs @@ -305,5 +305,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } + + [Fact] + public void Rgba32_PackFromRgba64_ToRgba64() + { + // arrange + var input = default(Rgba32); + 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/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index d8d6bcf8b..b10fecb5f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -150,5 +150,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } + + [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); + } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs index 1dd280bee..73f2dd126 100644 --- a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs @@ -6,7 +6,7 @@ using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; using Xunit; -namespace SixLabors.ImageSharp.Tests +namespace SixLabors.ImageSharp.Tests.PixelFormats { /// /// Tests the struct. @@ -126,5 +126,21 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(3, ordered[2]); Assert.Equal(4, ordered[3]); } + + [Fact] + public void RgbaVector_PackFromRgba64_ToRgba64() + { + // arrange + var input = default(RgbaVector); + 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/Short2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs index b38c33b2a..bfaf64204 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs @@ -169,5 +169,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } + + [Fact] + public void Short2_PackFromRgba64_ToRgba64() + { + // arrange + var input = default(Short2); + 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/Short4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs index 097a53331..f9e2f4b58 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs @@ -205,5 +205,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } + + [Fact] + public void Short4_PackFromRgba64_ToRgba64() + { + // arrange + var input = default(Short4); + 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); + } } } From 2ad603afc181f3be5cb6d7d985dbb34c664fd598 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 15 Jun 2018 11:07:11 +1000 Subject: [PATCH 07/30] Minor cleanup --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 6 +++-- .../PixelFormats/Rgba32.PixelOperations.cs | 22 +++++++++--------- src/ImageSharp/PixelFormats/Rgba32.cs | 5 +++- src/ImageSharp/PixelFormats/Rgba64.cs | 23 ++++++------------- .../PixelFormats/Rgba64Tests.cs | 2 +- 5 files changed, 27 insertions(+), 31 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index c122aa404..c544a29ac 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -861,7 +861,7 @@ namespace SixLabors.ImageSharp.Formats.Png var rgba = default(Rgba32); - if (this.paletteAlpha != null && this.paletteAlpha.Length > 0) + 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. @@ -949,7 +949,7 @@ namespace SixLabors.ImageSharp.Formats.Png var rgba = default(Rgba32); Span pal = MemoryMarshal.Cast(this.palette); - if (this.paletteAlpha != null && this.paletteAlpha.Length > 0) + 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. @@ -1165,6 +1165,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Reads a chunk from the stream. /// + /// The image format chunk. /// /// The . /// @@ -1255,6 +1256,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Skips the chunk data and the cycle redundancy chunk read from the data. /// + /// The image format chunk. private void SkipChunkDataAndCrc(in PngChunk chunk) { this.currentStream.Skip(chunk.Length); diff --git a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs index b1eba3275..508dc1f64 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs @@ -87,15 +87,15 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToVector4(ReadOnlySpan sourceColors, Span destVectors, int count) + internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) { Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); - Guard.MustBeSizedAtLeast(destVectors, count, nameof(destVectors)); + Guard.MustBeSizedAtLeast(destinationVectors, count, nameof(destinationVectors)); if (count < 256 || !Vector.IsHardwareAccelerated) { // Doesn't worth to bother with SIMD: - base.ToVector4(sourceColors, destVectors, count); + base.ToVector4(sourceColors, destinationVectors, count); return; } @@ -104,25 +104,25 @@ namespace SixLabors.ImageSharp.PixelFormats if (alignedCount > 0) { - ToVector4SimdAligned(sourceColors, destVectors, alignedCount); + ToVector4SimdAligned(sourceColors, destinationVectors, alignedCount); } if (remainder > 0) { sourceColors = sourceColors.Slice(alignedCount); - destVectors = destVectors.Slice(alignedCount); - base.ToVector4(sourceColors, destVectors, remainder); + destinationVectors = destinationVectors.Slice(alignedCount); + base.ToVector4(sourceColors, destinationVectors, remainder); } } /// - internal override void PackFromVector4(ReadOnlySpan sourceVectors, Span destColors, int count) + internal override void PackFromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) { - GuardSpans(sourceVectors, nameof(sourceVectors), destColors, nameof(destColors), count); + GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); if (!SimdUtils.IsAvx2CompatibleArchitecture) { - base.PackFromVector4(sourceVectors, destColors, count); + base.PackFromVector4(sourceVectors, destinationColors, count); return; } @@ -132,7 +132,7 @@ namespace SixLabors.ImageSharp.PixelFormats if (alignedCount > 0) { ReadOnlySpan flatSrc = MemoryMarshal.Cast(sourceVectors.Slice(0, alignedCount)); - Span flatDest = MemoryMarshal.Cast(destColors); + Span flatDest = MemoryMarshal.Cast(destinationColors); SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(flatSrc, flatDest); } @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats { // actually: remainder == 1 int lastIdx = count - 1; - destColors[lastIdx].PackFromVector4(sourceVectors[lastIdx]); + destinationColors[lastIdx].PackFromVector4(sourceVectors[lastIdx]); } } diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index 83ba6664f..12bbc34b8 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -199,7 +199,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// public uint PackedValue { + [MethodImpl(MethodImplOptions.AggressiveInlining)] get => this.Rgba; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] set => this.Rgba = value; } @@ -395,7 +398,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// public override bool Equals(object obj) { - return (obj is Rgba32) && this.Equals((Rgba32)obj); + return obj is Rgba32 rgba32 && this.Equals(rgba32); } /// diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/Rgba64.cs index a20a76c84..3202a5628 100644 --- a/src/ImageSharp/PixelFormats/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/Rgba64.cs @@ -88,13 +88,11 @@ namespace SixLabors.ImageSharp.PixelFormats public Rgba64(ulong packed) : this() { - this.Rgba = packed; + this.PackedValue = packed; } - /// - /// Gets or sets the packed representation of the struct. - /// - public ulong Rgba + /// + public ulong PackedValue { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Unsafe.As(ref this); @@ -103,13 +101,6 @@ namespace SixLabors.ImageSharp.PixelFormats set => Unsafe.As(ref this) = value; } - /// - public ulong PackedValue - { - get => this.Rgba; - set => this.Rgba = value; - } - /// /// Compares two objects for equality. /// @@ -125,7 +116,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Rgba64 left, Rgba64 right) { - return left.Rgba == right.Rgba; + return left.PackedValue == right.PackedValue; } /// @@ -143,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Rgba64 left, Rgba64 right) { - return left.Rgba != right.Rgba; + return left.PackedValue != right.PackedValue; } /// @@ -272,14 +263,14 @@ namespace SixLabors.ImageSharp.PixelFormats /// public override bool Equals(object obj) { - return (obj is Rgba64) && this.Equals((Rgba64)obj); + return obj is Rgba64 rgba64 && this.Equals(rgba64); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Rgba64 other) { - return this.Rgba == other.Rgba; + return this.PackedValue == other.PackedValue; } /// diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index b10fecb5f..c04352c32 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // arrange var pixel = default(Rgba64); var short4 = new Rgba64(Vector4.One); - ulong expected = 0xFFFFFFFFFFFFFFFF; + const ulong expected = 0xFFFFFFFFFFFFFFFF; // act Vector4 scaled = short4.ToScaledVector4(); From c4646b62ffb337a3625793dde5ea42dc606fa146 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 15 Jun 2018 12:14:58 +1000 Subject: [PATCH 08/30] Add Rgb48 --- src/ImageSharp/PixelFormats/Rgba48.cs | 249 ++++++++++++++++++++++++++ src/ImageSharp/PixelFormats/Rgba64.cs | 2 +- 2 files changed, 250 insertions(+), 1 deletion(-) create mode 100644 src/ImageSharp/PixelFormats/Rgba48.cs diff --git a/src/ImageSharp/PixelFormats/Rgba48.cs b/src/ImageSharp/PixelFormats/Rgba48.cs new file mode 100644 index 000000000..4408415b1 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Rgba48.cs @@ -0,0 +1,249 @@ +// 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 +{ + /// + /// Packed pixel type containing three 16-bit unsigned normalized values ranging from 0 to 635535. + /// + /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. + /// + /// + [StructLayout(LayoutKind.Sequential)] + public struct Rgba48 : IPixel + { + private const float Max = 65535F; + + /// + /// Gets or sets the red component. + /// + public ushort R; + + /// + /// Gets or sets the green component. + /// + public ushort G; + + /// + /// Gets or sets the blue component. + /// + public ushort B; + + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + public Rgba48(ushort r, ushort g, ushort b) + : this() + { + this.R = r; + this.G = g; + this.B = b; + } + + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + public Rgba48(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 Rgba48(Vector3 vector) + : this(vector.X, vector.Y, vector.Z) + { + } + + /// + /// 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 ==(Rgba48 left, Rgba48 right) + { + return left.R == right.R + && left.G == right.G + && left.B == right.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 not equal to the parameter; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(Rgba48 left, Rgba48 right) + { + return left.R != right.R + || left.G != right.G + || left.B != right.B; + } + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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(MethodImplOptions.AggressiveInlining)] + public void PackFromVector4(Vector4 vector) + { + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; + this.R = (ushort)MathF.Round(vector.X); + this.G = (ushort)MathF.Round(vector.Y); + this.B = (ushort)MathF.Round(vector.Z); + } + + /// + [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 PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [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(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + public override bool Equals(object obj) + { + return obj is Rgba48 rgba48 && this.Equals(rgba48); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Rgba48 other) + { + return this.R == other.R + && this.G == other.G + && this.B == other.B; + } + + /// + public override string ToString() => this.ToVector4().ToString(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() + { + return HashHelpers.Combine( + this.R.GetHashCode(), + HashHelpers.Combine(this.G.GetHashCode(), this.B.GetHashCode())); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/Rgba64.cs index 3202a5628..c059c6aa5 100644 --- a/src/ImageSharp/PixelFormats/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/Rgba64.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.PixelFormats { /// - /// Packed pixel type containing four 16-bit unsigned normalized values ranging from 0 to 1. + /// Packed pixel type containing four 16-bit unsigned normalized values ranging from 0 to 635535. /// /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. /// From 6ea2962f938b4e8900b40fa31e756673330f5a4a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 15 Jun 2018 12:17:39 +1000 Subject: [PATCH 09/30] Rgba48 => Rgb48 --- .../PixelFormats/{Rgba48.cs => Rgb48.cs} | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) rename src/ImageSharp/PixelFormats/{Rgba48.cs => Rgb48.cs} (85%) diff --git a/src/ImageSharp/PixelFormats/Rgba48.cs b/src/ImageSharp/PixelFormats/Rgb48.cs similarity index 85% rename from src/ImageSharp/PixelFormats/Rgba48.cs rename to src/ImageSharp/PixelFormats/Rgb48.cs index 4408415b1..7a8899a10 100644 --- a/src/ImageSharp/PixelFormats/Rgba48.cs +++ b/src/ImageSharp/PixelFormats/Rgb48.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// [StructLayout(LayoutKind.Sequential)] - public struct Rgba48 : IPixel + public struct Rgb48 : IPixel { private const float Max = 65535F; @@ -35,12 +35,12 @@ namespace SixLabors.ImageSharp.PixelFormats public ushort B; /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The red component. /// The green component. /// The blue component. - public Rgba48(ushort r, ushort g, ushort b) + public Rgb48(ushort r, ushort g, ushort b) : this() { this.R = r; @@ -49,12 +49,12 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The red component. /// The green component. /// The blue component. - public Rgba48(float r, float g, float b) + public Rgb48(float r, float g, float b) : this() { this.R = (ushort)MathF.Round(r.Clamp(0, 1) * Max); @@ -63,24 +63,24 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The vector containing the components values. - public Rgba48(Vector3 vector) + public Rgb48(Vector3 vector) : this(vector.X, vector.Y, vector.Z) { } /// - /// 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 ==(Rgba48 left, Rgba48 right) + public static bool operator ==(Rgb48 left, Rgb48 right) { return left.R == right.R && left.G == right.G @@ -88,15 +88,15 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// 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 !=(Rgba48 left, Rgba48 right) + public static bool operator !=(Rgb48 left, Rgb48 right) { return left.R != right.R || left.G != right.G @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -222,12 +222,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// public override bool Equals(object obj) { - return obj is Rgba48 rgba48 && this.Equals(rgba48); + return obj is Rgb48 Rgb48 && this.Equals(Rgb48); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgba48 other) + public bool Equals(Rgb48 other) { return this.R == other.R && this.G == other.G From 332dd70cfb633b08405d32b6dcfe14c72bfc9930 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 15 Jun 2018 14:28:43 +1000 Subject: [PATCH 10/30] Add Rgb48 tests --- src/ImageSharp/PixelFormats/Rgb48.cs | 2 +- .../PixelFormats/Rgb48Tests.cs | 168 ++++++++++++++++++ 2 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs diff --git a/src/ImageSharp/PixelFormats/Rgb48.cs b/src/ImageSharp/PixelFormats/Rgb48.cs index 7a8899a10..f5cc62b9d 100644 --- a/src/ImageSharp/PixelFormats/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/Rgb48.cs @@ -222,7 +222,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// public override bool Equals(object obj) { - return obj is Rgb48 Rgb48 && this.Equals(Rgb48); + return obj is Rgb48 rgb48 && this.Equals(rgb48); } /// diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs new file mode 100644 index 000000000..da0082e45 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -0,0 +1,168 @@ +// 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, 115); + + // act + rgba48.ToRgba32(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, 115); + + // 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_PackFromRgba64_ToRgba64() + { + // arrange + var input = default(Rgb48); + 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); + } + } +} From 2a7bde5e0f35bc9a754594471c1192f1564807d4 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 15 Jun 2018 14:39:56 +1000 Subject: [PATCH 11/30] Fix tests --- src/ImageSharp/PixelFormats/Rgba32.cs | 5 +---- tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs | 6 +++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index 12bbc34b8..430d57602 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -408,10 +408,7 @@ namespace SixLabors.ImageSharp.PixelFormats return this.Rgba == other.Rgba; } - /// - /// 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})"; diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index da0082e45..61203a12b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // arrange var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 76, 115); + var expected = new Rgba32(20, 38, 76, 255); // act rgba48.ToRgba32(ref actual); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // arrange var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); var actual = default(Bgra32); - var expected = new Bgra32(20, 38, 76, 115); + var expected = new Bgra32(20, 38, 76, 255); // act rgba48.ToBgra32(ref actual); @@ -155,7 +155,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // arrange var input = default(Rgb48); var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); + var expected = new Rgba64(65535, 0, 65535, 65535); // act input.PackFromRgba64(expected); From 3049324ce7bfe60e05a22293754194ff9f22d5e0 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 15 Jun 2018 15:23:59 +1000 Subject: [PATCH 12/30] Add IPixel Rgb48 methods --- src/ImageSharp/PixelFormats/Alpha8.cs | 20 +++++- src/ImageSharp/PixelFormats/Argb32.cs | 8 +++ src/ImageSharp/PixelFormats/Bgr24.cs | 8 +++ src/ImageSharp/PixelFormats/Bgr565.cs | 14 +++- src/ImageSharp/PixelFormats/Bgra32.cs | 18 ++--- src/ImageSharp/PixelFormats/Bgra4444.cs | 8 +++ src/ImageSharp/PixelFormats/Bgra5551.cs | 8 +++ src/ImageSharp/PixelFormats/Byte4.cs | 8 +++ .../PixelOperations{TPixel}.Generated.cs | 71 +++++++++++++++++++ .../PixelOperations{TPixel}.Generated.tt | 45 ++++++++++++ src/ImageSharp/PixelFormats/HalfSingle.cs | 8 +++ 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 +++ src/ImageSharp/PixelFormats/Rg32.cs | 8 +++ src/ImageSharp/PixelFormats/Rgb24.cs | 13 ++-- src/ImageSharp/PixelFormats/Rgb48.cs | 8 +++ src/ImageSharp/PixelFormats/Rgba1010102.cs | 8 +++ src/ImageSharp/PixelFormats/Rgba32.cs | 8 +++ src/ImageSharp/PixelFormats/Rgba64.cs | 18 ++--- src/ImageSharp/PixelFormats/RgbaVector.cs | 8 +++ src/ImageSharp/PixelFormats/Short2.cs | 10 ++- src/ImageSharp/PixelFormats/Short4.cs | 8 +++ 27 files changed, 340 insertions(+), 25 deletions(-) diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/Alpha8.cs index 0328e8bb3..c8534ae22 100644 --- a/src/ImageSharp/PixelFormats/Alpha8.cs +++ b/src/ImageSharp/PixelFormats/Alpha8.cs @@ -155,13 +155,31 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = this.PackedValue; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgb48(Rgb48 source) => this.PackedValue = byte.MaxValue; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgb48(ref Rgb48 dest) + { + dest.R = 0; + dest.G = 0; + dest.B = 0; + } + /// [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()); + public void ToRgba64(ref Rgba64 dest) + { + dest.R = 0; + dest.G = 0; + dest.B = 0; + } /// /// Compares an object with the packed vector. diff --git a/src/ImageSharp/PixelFormats/Argb32.cs b/src/ImageSharp/PixelFormats/Argb32.cs index ca16be93b..bd4c93d28 100644 --- a/src/ImageSharp/PixelFormats/Argb32.cs +++ b/src/ImageSharp/PixelFormats/Argb32.cs @@ -310,6 +310,14 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public Argb32 ToArgb32() => this; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Bgr24.cs b/src/ImageSharp/PixelFormats/Bgr24.cs index 01df05552..13673aa47 100644 --- a/src/ImageSharp/PixelFormats/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/Bgr24.cs @@ -177,6 +177,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Bgr565.cs b/src/ImageSharp/PixelFormats/Bgr565.cs index 755590bfe..8595c6b9b 100644 --- a/src/ImageSharp/PixelFormats/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/Bgr565.cs @@ -187,6 +187,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)MathF.Round(vector.W); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -231,9 +239,9 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] private static ushort Pack(float x, float y, float z) { - 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)); + 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)); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Bgra32.cs b/src/ImageSharp/PixelFormats/Bgra32.cs index e51948996..86a141bc5 100644 --- a/src/ImageSharp/PixelFormats/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/Bgra32.cs @@ -219,17 +219,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - dest = Unsafe.As(ref this); - } + public void ToBgr24(ref Bgr24 dest) => dest = Unsafe.As(ref this); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - dest = this; - } + public void ToBgra32(ref Bgra32 dest) => dest = this; /// /// Converts the pixel to format. @@ -252,6 +246,14 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public Bgra32 ToBgra32() => this; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Bgra4444.cs b/src/ImageSharp/PixelFormats/Bgra4444.cs index 75717ec8b..b006aa5d2 100644 --- a/src/ImageSharp/PixelFormats/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/Bgra4444.cs @@ -178,6 +178,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Bgra5551.cs b/src/ImageSharp/PixelFormats/Bgra5551.cs index 8f673d1dc..efaf05613 100644 --- a/src/ImageSharp/PixelFormats/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/Bgra5551.cs @@ -178,6 +178,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Byte4.cs b/src/ImageSharp/PixelFormats/Byte4.cs index bc662cef9..48430d17a 100644 --- a/src/ImageSharp/PixelFormats/Byte4.cs +++ b/src/ImageSharp/PixelFormats/Byte4.cs @@ -179,6 +179,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs index 2656f9a3a..f644fbefb 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs @@ -82,6 +82,77 @@ namespace SixLabors.ImageSharp.PixelFormats this.ToRgba64(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 PackFromRgb48(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); + + var rgb = default(Rgb48); + + 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); + } + } + + /// + /// 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) + { + 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. + /// The number of pixels to convert. + internal virtual void ToRgb48(ReadOnlySpan sourcePixels, Span dest, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + + ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destBaseRef = ref MemoryMarshal.GetReference(dest); + + 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); + sp.ToRgb48(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 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. /// diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt index f73f37eb8..1a6ac60f5 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt @@ -93,6 +93,48 @@ <# } + 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) { #> @@ -237,6 +279,9 @@ namespace SixLabors.ImageSharp.PixelFormats GeneratePackFromMethodUsingPackFromRgba64("Rgba64", "rgba = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Rgba64"); + GeneratePackFromMethodUsingPackFromRgb48("Rgb48", "rgb = Unsafe.Add(ref sourceRef, i);"); + GenerateToDestFormatMethods("Rgb48"); + GeneratePackFromMethodUsingPackFromRgba32("Rgba32", "rgba = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Rgba32"); diff --git a/src/ImageSharp/PixelFormats/HalfSingle.cs b/src/ImageSharp/PixelFormats/HalfSingle.cs index 7f0dff07a..504992542 100644 --- a/src/ImageSharp/PixelFormats/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/HalfSingle.cs @@ -192,6 +192,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/HalfVector2.cs b/src/ImageSharp/PixelFormats/HalfVector2.cs index 0f4b06a0f..72eb4f79c 100644 --- a/src/ImageSharp/PixelFormats/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/HalfVector2.cs @@ -207,6 +207,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/HalfVector4.cs b/src/ImageSharp/PixelFormats/HalfVector4.cs index 745f48a91..62a25bc2b 100644 --- a/src/ImageSharp/PixelFormats/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/HalfVector4.cs @@ -200,6 +200,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index 5bb9b1a7f..ae09af626 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -61,6 +61,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// The value. void PackFromRgba32(Rgba32 source); + /// + /// Packs the pixel from an value. + /// + /// The value. + void PackFromRgb48(Rgb48 source); + /// /// Packs the pixel from an value. /// @@ -91,6 +97,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// 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. /// diff --git a/src/ImageSharp/PixelFormats/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/NormalizedByte2.cs index 306894b11..75a907594 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte2.cs @@ -226,6 +226,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/NormalizedByte4.cs index 620f3191d..fc3845eb2 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte4.cs @@ -219,6 +219,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/NormalizedShort2.cs index 38df71523..2ddc83e76 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort2.cs @@ -213,6 +213,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/NormalizedShort4.cs index dc6587900..25b26fa7f 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort4.cs @@ -221,6 +221,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)MathF.Round(vector.W); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Rg32.cs b/src/ImageSharp/PixelFormats/Rg32.cs index 0efacd0dd..39a0ff424 100644 --- a/src/ImageSharp/PixelFormats/Rg32.cs +++ b/src/ImageSharp/PixelFormats/Rg32.cs @@ -191,6 +191,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Rgb24.cs b/src/ImageSharp/PixelFormats/Rgb24.cs index c3b870dff..c3ad82755 100644 --- a/src/ImageSharp/PixelFormats/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/Rgb24.cs @@ -136,10 +136,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest = this; - } + public void ToRgb24(ref Rgb24 dest) => dest = this; /// public void ToRgba32(ref Rgba32 dest) @@ -174,6 +171,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Rgb48.cs b/src/ImageSharp/PixelFormats/Rgb48.cs index f5cc62b9d..e4c1345d2 100644 --- a/src/ImageSharp/PixelFormats/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/Rgb48.cs @@ -215,6 +215,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)MathF.Round(vector.W); } + /// + [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) => dest.PackFromScaledVector4(this.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Rgba1010102.cs b/src/ImageSharp/PixelFormats/Rgba1010102.cs index adaec7051..f603a217a 100644 --- a/src/ImageSharp/PixelFormats/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/Rgba1010102.cs @@ -185,6 +185,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)MathF.Round(vector.W); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index 430d57602..c585dbfda 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -387,6 +387,14 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32 ToRgba32() => this; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/Rgba64.cs index c059c6aa5..3ff22de63 100644 --- a/src/ImageSharp/PixelFormats/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/Rgba64.cs @@ -195,10 +195,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) - { - this = source; - } + public void PackFromRgba64(Rgba64 source) => this = source; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -223,10 +220,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) - { - dest = this; - } + 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)] + public void ToRgba64(ref Rgba64 dest) => dest = this; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/RgbaVector.cs b/src/ImageSharp/PixelFormats/RgbaVector.cs index 637a5f362..dd5f77b80 100644 --- a/src/ImageSharp/PixelFormats/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/RgbaVector.cs @@ -298,6 +298,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)MathF.Round(vector.W); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Short2.cs b/src/ImageSharp/PixelFormats/Short2.cs index 593132d2b..c298c5a48 100644 --- a/src/ImageSharp/PixelFormats/Short2.cs +++ b/src/ImageSharp/PixelFormats/Short2.cs @@ -207,7 +207,15 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } - /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Short4.cs b/src/ImageSharp/PixelFormats/Short4.cs index 3daabe9ba..41371362e 100644 --- a/src/ImageSharp/PixelFormats/Short4.cs +++ b/src/ImageSharp/PixelFormats/Short4.cs @@ -213,6 +213,14 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)MathF.Round(vector.W); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); From aee47781fb45f4691a9dd28ce18eaadd2de17877 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 15 Jun 2018 17:00:44 +1000 Subject: [PATCH 13/30] Use Rgb48 for 16 bit png decoding. --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 333 +++++++++--------- src/ImageSharp/PixelFormats/Bgra5551.cs | 8 +- src/ImageSharp/PixelFormats/Rgba64.cs | 12 + .../Formats/Png/PngDecoderTests.cs | 6 +- 4 files changed, 181 insertions(+), 178 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index c544a29ac..0f6db2561 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Buffers; using System.Buffers.Binary; using System.Collections.Generic; using System.IO; @@ -162,10 +161,15 @@ namespace SixLabors.ImageSharp.Formats.Png private PngColorType pngColorType; /// - /// Represents any color in an Rgb24 encoded png that should be transparent + /// 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 a grayscale encoded png that should be transparent /// @@ -370,14 +374,15 @@ namespace SixLabors.ImageSharp.Formats.Png } /// - /// Reads an integer value from 2 consecutive bytes in LSB order + /// Reads the least significant bits from the byte pair with the others set to 0. /// /// The source buffer /// THe offset /// The - public static int ReadIntFrom2Bytes(byte[] buffer, int offset) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte ReadByteLittleEndian(ReadOnlySpan buffer, int offset) { - return ((buffer[offset] & 0xFF) << 16) | (buffer[offset + 1] & 0xFF); + return (byte)(((buffer[offset] & 0xFF) << 16) | (buffer[offset + 1] & 0xFF)); } /// @@ -532,9 +537,8 @@ namespace SixLabors.ImageSharp.Formats.Png this.currentRowBytesRead = 0; Span scanlineSpan = this.scanline.Span; - var filterType = (FilterType)scanlineSpan[0]; - switch (filterType) + switch ((FilterType)scanlineSpan[0]) { case FilterType.None: break; @@ -607,9 +611,8 @@ namespace SixLabors.ImageSharp.Formats.Png Span scanSpan = this.scanline.Slice(0, bytesPerInterlaceScanline); Span prevSpan = this.previousScanline.Slice(0, bytesPerInterlaceScanline); - var filterType = (FilterType)scanSpan[0]; - switch (filterType) + switch ((FilterType)scanSpan[0]) { case FilterType.None: break; @@ -726,12 +729,14 @@ namespace SixLabors.ImageSharp.Formats.Png { if (this.header.BitDepth == 16) { - int length = this.header.Width * 3; - using (IBuffer compressed = this.configuration.MemoryManager.Allocate(length)) + Rgb48 rgb48 = default; + for (int x = 0, o = 0; x < this.header.Width; x++, o += 6) { - // TODO: Should we use pack from vector here instead? - this.From16BitTo8Bit(scanlineBuffer, compressed.Span, length); - PixelOperations.Instance.PackFromRgb24Bytes(compressed.Span, rowSpan, this.header.Width); + rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2)); + rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2)); + rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 4, 2)); + color.PackFromRgb48(rgb48); + rowSpan[x] = color; } } else @@ -743,23 +748,19 @@ namespace SixLabors.ImageSharp.Formats.Png { if (this.header.BitDepth == 16) { - int length = this.header.Width * 3; - using (IBuffer compressed = this.configuration.MemoryManager.Allocate(length)) + Rgb48 rgb48 = default; + Rgba64 rgba64 = default; + for (int x = 0, o = 0; x < this.header.Width; x++, o += 6) { - // TODO: Should we use pack from vector here instead? - this.From16BitTo8Bit(scanlineBuffer, compressed.Span, length); - - Span rgb24Span = MemoryMarshal.Cast(compressed.Span); - for (int x = 0; x < this.header.Width; x++) - { - ref Rgb24 rgb24 = ref rgb24Span[x]; - var rgba32 = default(Rgba32); - rgba32.Rgb = rgb24; - rgba32.A = (byte)(rgb24.Equals(this.rgb24Trans) ? 0 : 255); - - color.PackFromRgba32(rgba32); - rowSpan[x] = color; - } + rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2)); + rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2)); + rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 4, 2)); + + rgba64.Rgb = rgb48; + rgba64.A = rgb48.Equals(this.rgb48Trans) ? ushort.MinValue : ushort.MaxValue; + + color.PackFromRgba64(rgba64); + rowSpan[x] = color; } } else @@ -768,9 +769,9 @@ namespace SixLabors.ImageSharp.Formats.Png for (int x = 0; x < this.header.Width; x++) { ref readonly Rgb24 rgb24 = ref rgb24Span[x]; - var rgba32 = default(Rgba32); + Rgba32 rgba32 = default; rgba32.Rgb = rgb24; - rgba32.A = (byte)(rgb24.Equals(this.rgb24Trans) ? 0 : 255); + rgba32.A = rgb24.Equals(this.rgb24Trans) ? byte.MinValue : byte.MaxValue; color.PackFromRgba32(rgba32); rowSpan[x] = color; @@ -804,94 +805,6 @@ namespace SixLabors.ImageSharp.Formats.Png } } - /// - /// Compresses the given span from 16bpp to 8bpp - /// - /// The source buffer - /// The target buffer - /// The target length - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void From16BitTo8Bit(ReadOnlySpan source, Span target, int length) - { - for (int i = 0, j = 0; i < length; i++, j += 2) - { - target[i] = (byte)((source[j + 1] << 8) + source[j]); - } - } - - /// - /// Decodes and assigns marker colors that identify transparent pixels in non indexed images - /// - /// The aplha tRNS array - private void AssignTransparentMarkers(byte[] alpha) - { - if (this.pngColorType == PngColorType.Rgb) - { - if (alpha.Length >= 6) - { - byte r = (byte)ReadIntFrom2Bytes(alpha, 0); - byte g = (byte)ReadIntFrom2Bytes(alpha, 2); - byte b = (byte)ReadIntFrom2Bytes(alpha, 4); - this.rgb24Trans = new Rgb24(r, g, b); - this.hasTrans = true; - } - } - else if (this.pngColorType == PngColorType.Grayscale) - { - if (alpha.Length >= 2) - { - this.intensityTrans = (byte)ReadIntFrom2Bytes(alpha, 0); - this.hasTrans = true; - } - } - } - - /// - /// Processes a scanline that uses a palette - /// - /// The type of pixel we are expanding to - /// The scanline - /// Thecurrent output image row - private void ProcessScanlineFromPalette(ReadOnlySpan defilteredScanline, Span row) - where TPixel : struct, IPixel - { - ReadOnlySpan newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth); - ReadOnlySpan pal = MemoryMarshal.Cast(this.palette); - var color = default(TPixel); - - var rgba = default(Rgba32); - - 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. - for (int x = 0; x < this.header.Width; x++) - { - int index = newScanline[x]; - - rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255; - rgba.Rgb = pal[index]; - - color.PackFromRgba32(rgba); - row[x] = color; - } - } - else - { - rgba.A = 255; - - for (int x = 0; x < this.header.Width; x++) - { - int index = newScanline[x]; - - rgba.Rgb = pal[index]; - - color.PackFromRgba32(rgba); - row[x] = color; - } - } - } - /// /// Processes the interlaced de-filtered scanline filling the image pixel data /// @@ -946,18 +859,17 @@ namespace SixLabors.ImageSharp.Formats.Png case PngColorType.Palette: ReadOnlySpan newScanline = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth); - var rgba = default(Rgba32); Span pal = MemoryMarshal.Cast(this.palette); 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; for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++) { int index = newScanline[o]; - - rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255; + rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : byte.MaxValue; rgba.Rgb = pal[index]; color.PackFromRgba32(rgba); @@ -966,13 +878,12 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - rgba.A = 255; - + var rgba = new Rgba32(0, 0, 0, 255); for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++) { int index = newScanline[o]; - rgba.Rgb = pal[index]; + color.PackFromRgba32(rgba); rowSpan[x] = color; } @@ -982,42 +893,35 @@ namespace SixLabors.ImageSharp.Formats.Png case PngColorType.Rgb: - rgba.A = 255; - if (this.header.BitDepth == 16) { - int length = this.header.Width * 3; - using (IBuffer compressed = this.configuration.MemoryManager.Allocate(length)) + if (this.hasTrans) { - Span compressedSpan = compressed.Span; + Rgb48 rgb48 = default; + Rgba64 rgba64 = default; + for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 6) + { + rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2)); + rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2)); + rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 4, 2)); - // TODO: Should we use pack from vector here instead? - this.From16BitTo8Bit(scanlineBuffer, compressedSpan, length); + rgba64.Rgb = rgb48; + rgba64.A = rgb48.Equals(this.rgb48Trans) ? ushort.MinValue : ushort.MaxValue; - if (this.hasTrans) - { - for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 3) - { - rgba.R = compressedSpan[o]; - rgba.G = compressedSpan[o + 1]; - rgba.B = compressedSpan[o + 2]; - rgba.A = (byte)(this.rgb24Trans.Equals(rgba.Rgb) ? 0 : 255); - - color.PackFromRgba32(rgba); - rowSpan[x] = color; - } + color.PackFromRgba64(rgba64); + rowSpan[x] = color; } - else + } + else + { + Rgb48 rgb48 = default; + for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 6) { - for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 3) - { - rgba.R = compressedSpan[o]; - rgba.G = compressedSpan[o + 1]; - rgba.B = compressedSpan[o + 2]; - - color.PackFromRgba32(rgba); - rowSpan[x] = color; - } + rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2)); + rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2)); + rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 4, 2)); + color.PackFromRgb48(rgb48); + rowSpan[x] = color; } } } @@ -1025,12 +929,13 @@ namespace SixLabors.ImageSharp.Formats.Png { if (this.hasTrans) { + Rgba32 rgba = default; for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += this.bytesPerPixel) { rgba.R = scanlineBuffer[o]; rgba.G = scanlineBuffer[o + this.bytesPerSample]; rgba.B = scanlineBuffer[o + (2 * this.bytesPerSample)]; - rgba.A = (byte)(this.rgb24Trans.Equals(rgba.Rgb) ? 0 : 255); + rgba.A = this.rgb24Trans.Equals(rgba.Rgb) ? byte.MinValue : byte.MaxValue; color.PackFromRgba32(rgba); rowSpan[x] = color; @@ -1038,6 +943,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { + var rgba = new Rgba32(0, 0, 0, 255); for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += this.bytesPerPixel) { rgba.R = scanlineBuffer[o]; @@ -1069,6 +975,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { + Rgba32 rgba = default; for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += this.bytesPerPixel) { rgba.R = scanlineBuffer[o]; @@ -1086,33 +993,87 @@ namespace SixLabors.ImageSharp.Formats.Png } /// - /// Reads a text chunk containing image properties from the data. + /// Decodes and assigns marker colors that identify transparent pixels in non indexed images /// - /// The metadata to decode to. - /// The containing data. - /// The maximum length to read. - private void ReadTextChunk(ImageMetaData metadata, byte[] data, int length) + /// The aplha tRNS array + private void AssignTransparentMarkers(ReadOnlySpan alpha) { - if (this.ignoreMetadata) + if (this.pngColorType == PngColorType.Rgb) { - return; + if (alpha.Length >= 6) + { + if (this.header.BitDepth == 16) + { + 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; + } + + 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; + } + } + else if (this.pngColorType == PngColorType.Grayscale) + { + // TODO: 16 bit + if (alpha.Length >= 2) + { + this.intensityTrans = ReadByteLittleEndian(alpha, 0); + this.hasTrans = true; + } } + } - int zeroIndex = 0; + /// + /// Processes a scanline that uses a palette + /// + /// The type of pixel we are expanding to + /// The scanline + /// Thecurrent output image row + private void ProcessScanlineFromPalette(ReadOnlySpan defilteredScanline, Span row) + where TPixel : struct, IPixel + { + ReadOnlySpan newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth); + ReadOnlySpan pal = MemoryMarshal.Cast(this.palette); + var color = default(TPixel); - for (int i = 0; i < length; i++) + var rgba = default(Rgba32); + + if (this.paletteAlpha?.Length > 0) { - if (data[i] == 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. + for (int x = 0; x < this.header.Width; x++) { - zeroIndex = i; - break; + int index = newScanline[x]; + + rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255; + rgba.Rgb = pal[index]; + + color.PackFromRgba32(rgba); + row[x] = color; } } + else + { + rgba.A = 255; - string name = this.textEncoding.GetString(data, 0, zeroIndex); - string value = this.textEncoding.GetString(data, zeroIndex + 1, length - zeroIndex - 1); + for (int x = 0; x < this.header.Width; x++) + { + int index = newScanline[x]; - metadata.Properties.Add(new ImageProperty(name, value)); + rgba.Rgb = pal[index]; + + color.PackFromRgba32(rgba); + row[x] = color; + } + } } /// @@ -1162,6 +1123,36 @@ namespace SixLabors.ImageSharp.Formats.Png this.pngColorType = this.header.ColorType; } + /// + /// 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) + { + if (this.ignoreMetadata) + { + return; + } + + int zeroIndex = 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); + + metadata.Properties.Add(new ImageProperty(name, value)); + } + /// /// Reads a chunk from the stream. /// diff --git a/src/ImageSharp/PixelFormats/Bgra5551.cs b/src/ImageSharp/PixelFormats/Bgra5551.cs index efaf05613..90a625142 100644 --- a/src/ImageSharp/PixelFormats/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/Bgra5551.cs @@ -238,10 +238,10 @@ namespace SixLabors.ImageSharp.PixelFormats private static ushort Pack(float x, float y, float z, float w) { 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(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)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/Rgba64.cs index 3ff22de63..cdc3f38b2 100644 --- a/src/ImageSharp/PixelFormats/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/Rgba64.cs @@ -91,6 +91,18 @@ namespace SixLabors.ImageSharp.PixelFormats this.PackedValue = packed; } + /// + /// Gets or sets the RGB components of this struct as + /// + public Rgb48 Rgb + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Unsafe.As(ref this); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => Unsafe.As(ref this) = value; + } + /// public ulong PackedValue { diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index f97e115b7..02fcd1643 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.Tests { TestImages.Png.Bad.ChunkLength2, TestImages.Png.VimImage2, - TestImages.Png.Splash, + TestImages.Png.Splash, TestImages.Png.Indexed, TestImages.Png.Bad.ChunkLength1, TestImages.Png.VersioningImage1, @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.Tests } } } - + [Theory] [WithFile(TestImages.Png.Interlaced, PixelTypes.Rgba32)] public void Decode_Interlaced_DoesNotThrow(TestImageProvider provider) @@ -143,7 +143,7 @@ namespace SixLabors.ImageSharp.Tests } // TODO: We need to decode these into Rgba64 properly, and do 'CompareToOriginal' in a Rgba64 mode! (See #285) - [Theory] + [Theory(Skip = "Skipped for now until we can update the reference images from libpng samples.")] [WithFileCollection(nameof(TestImages48Bpp), PixelTypes.Rgba32)] public void Decode_48Bpp(TestImageProvider provider) where TPixel : struct, IPixel From 97012b96ce9b8acda1e04046c4c893c0050e5b1b Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 16 Jun 2018 01:43:07 +1000 Subject: [PATCH 14/30] Can now decode all bit depths. --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 262 +++++++++++++++---- 1 file changed, 210 insertions(+), 52 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 0f6db2561..1d3fc0fd9 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -28,10 +28,10 @@ namespace SixLabors.ImageSharp.Formats.Png /// private static readonly Dictionary ColorTypes = new Dictionary() { - [PngColorType.Grayscale] = new byte[] { 1, 2, 4, 8 }, + [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 }, + [PngColorType.GrayscaleWithAlpha] = new byte[] { 8, 16 }, [PngColorType.RgbWithAlpha] = new byte[] { 8, 16 } }; @@ -171,9 +171,14 @@ namespace SixLabors.ImageSharp.Formats.Png private Rgb48 rgb48Trans; /// - /// Represents any color in a grayscale encoded png that should be transparent + /// Represents any color in an 8 bit grayscale encoded png that should be transparent /// - private byte intensityTrans; + 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 @@ -353,6 +358,7 @@ namespace SixLabors.ImageSharp.Formats.Png return source; } + // TODO: We should be pooling this. byte[] result = new byte[bytesPerScanline * 8 / bits]; int mask = 0xFF >> (8 - bits); int resultOffset = 0; @@ -450,30 +456,20 @@ namespace SixLabors.ImageSharp.Formats.Png switch (this.pngColorType) { case PngColorType.Grayscale: - return 1; + return this.header.BitDepth == 16 ? 2 : 1; case PngColorType.GrayscaleWithAlpha: - return 2; + return this.header.BitDepth == 16 ? 4 : 2; case PngColorType.Palette: return 1; case PngColorType.Rgb: - if (this.header.BitDepth == 16) - { - return 6; - } - - return 3; + return this.header.BitDepth == 16 ? 6 : 3; case PngColorType.RgbWithAlpha: default: - if (this.header.BitDepth == 16) - { - return 8; - } - - return 4; + return this.header.BitDepth == 16 ? 8 : 4; } } @@ -682,37 +678,111 @@ namespace SixLabors.ImageSharp.Formats.Png switch (this.pngColorType) { case PngColorType.Grayscale: + int factor = 255 / ((int)Math.Pow(2, this.header.BitDepth) - 1); - ReadOnlySpan newScanline1 = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth); + ReadOnlySpan scanline = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth); - for (int x = 0; x < this.header.Width; x++) + if (!this.hasTrans) { - byte intensity = (byte)(newScanline1[x] * factor); - if (this.hasTrans && intensity == this.intensityTrans) + if (this.header.BitDepth == 16) { - color.PackFromRgba32(new Rgba32(intensity, intensity, intensity, 0)); + Rgb48 rgb48 = default; + for (int x = 0, o = 0; x < this.header.Width; x++, o += 2) + { + ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2)); + rgb48.R = luminance; + rgb48.G = luminance; + rgb48.B = luminance; + color.PackFromRgb48(rgb48); + rowSpan[x] = color; + } } else { - color.PackFromRgba32(new Rgba32(intensity, intensity, intensity)); + // 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)(scanline[x] * factor); + rgba32.R = luminance; + rgba32.G = luminance; + rgba32.B = luminance; + color.PackFromRgba32(rgba32); + rowSpan[x] = color; + } } + } + 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(scanlineBuffer.Slice(o, 2)); + rgba64.R = luminance; + rgba64.G = luminance; + rgba64.B = luminance; + rgba64.A = luminance.Equals(this.luminance16Trans) ? ushort.MinValue : ushort.MaxValue; - rowSpan[x] = color; + color.PackFromRgba64(rgba64); + rowSpan[x] = color; + } + } + else + { + Rgba32 rgba32 = default; + for (int x = 0; x < this.header.Width; x++) + { + byte luminance = (byte)(scanline[x] * factor); + rgba32.R = luminance; + rgba32.G = luminance; + rgba32.B = luminance; + rgba32.A = luminance.Equals(this.luminanceTrans) ? byte.MinValue : byte.MaxValue; + + color.PackFromRgba32(rgba32); + rowSpan[x] = color; + } + } } break; case PngColorType.GrayscaleWithAlpha: - for (int x = 0; x < this.header.Width; x++) + 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(scanlineBuffer.Slice(o, 2)); + ushort alpha = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2)); + rgba64.R = luminance; + rgba64.G = luminance; + rgba64.B = luminance; + rgba64.A = alpha; + + color.PackFromRgba64(rgba64); + rowSpan[x] = color; + } + } + else { - int offset = x * this.bytesPerPixel; + Rgba32 rgba32 = default; + for (int x = 0; x < this.header.Width; x++) + { + int offset = x * this.bytesPerPixel; + byte luminance = scanlineBuffer[offset]; + byte alpha = scanlineBuffer[offset + this.bytesPerSample]; - byte intensity = scanlineBuffer[offset]; - byte alpha = scanlineBuffer[offset + this.bytesPerSample]; + rgba32.R = luminance; + rgba32.G = luminance; + rgba32.B = luminance; + rgba32.A = alpha; - color.PackFromRgba32(new Rgba32(intensity, intensity, intensity, alpha)); - rowSpan[x] = color; + color.PackFromRgba32(rgba32); + rowSpan[x] = color; + } } break; @@ -824,34 +894,112 @@ namespace SixLabors.ImageSharp.Formats.Png switch (this.pngColorType) { case PngColorType.Grayscale: + int factor = 255 / ((int)Math.Pow(2, this.header.BitDepth) - 1); - ReadOnlySpan newScanline1 = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth); + ReadOnlySpan scanline = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth); - for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++) + if (!this.hasTrans) { - byte intensity = (byte)(newScanline1[o] * factor); - if (this.hasTrans && intensity == this.intensityTrans) + if (this.header.BitDepth == 16) { - color.PackFromRgba32(new Rgba32(intensity, intensity, intensity, 0)); + Rgb48 rgb48 = default; + for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 2) + { + ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2)); + rgb48.R = luminance; + rgb48.G = luminance; + rgb48.B = luminance; + + color.PackFromRgb48(rgb48); + rowSpan[x] = color; + } } else { - color.PackFromRgba32(new Rgba32(intensity, intensity, intensity)); + // 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)(scanline[o] * factor); + rgba32.R = luminance; + rgba32.G = luminance; + rgba32.B = luminance; + + color.PackFromRgba32(rgba32); + rowSpan[x] = color; + } } + } + 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(scanlineBuffer.Slice(o, 2)); + rgba64.R = luminance; + rgba64.G = luminance; + rgba64.B = luminance; + rgba64.A = luminance.Equals(this.luminance16Trans) ? ushort.MinValue : ushort.MaxValue; + + color.PackFromRgba64(rgba64); + rowSpan[x] = color; + } + } + else + { + Rgba32 rgba32 = default; + for (int x = pixelOffset; x < this.header.Width; x += increment) + { + byte luminance = (byte)(scanline[x] * factor); + rgba32.R = luminance; + rgba32.G = luminance; + rgba32.B = luminance; + rgba32.A = luminance.Equals(this.luminanceTrans) ? byte.MinValue : byte.MaxValue; - rowSpan[x] = color; + color.PackFromRgba32(rgba32); + rowSpan[x] = color; + } + } } break; case PngColorType.GrayscaleWithAlpha: - for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += this.bytesPerPixel) + if (this.header.BitDepth == 16) { - byte intensity = scanlineBuffer[o]; - byte alpha = scanlineBuffer[o + this.bytesPerSample]; - color.PackFromRgba32(new Rgba32(intensity, intensity, intensity, alpha)); - rowSpan[x] = color; + Rgba64 rgba64 = default; + for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 4) + { + ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2)); + ushort alpha = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2)); + rgba64.R = luminance; + rgba64.G = luminance; + rgba64.B = luminance; + rgba64.A = alpha; + + color.PackFromRgba64(rgba64); + rowSpan[x] = color; + } + } + else + { + Rgba32 rgba32 = default; + for (int x = pixelOffset; x < this.header.Width; x += increment) + { + int offset = x * this.bytesPerPixel; + byte luminance = scanlineBuffer[offset]; + byte alpha = scanlineBuffer[offset + this.bytesPerSample]; + rgba32.R = luminance; + rgba32.G = luminance; + rgba32.B = luminance; + rgba32.A = alpha; + + color.PackFromRgba32(rgba32); + rowSpan[x] = color; + } } break; @@ -878,7 +1026,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - var rgba = new Rgba32(0, 0, 0, 255); + var rgba = new Rgba32(0, 0, 0, byte.MaxValue); for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++) { int index = newScanline[o]; @@ -943,7 +1091,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - var rgba = new Rgba32(0, 0, 0, 255); + 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 = scanlineBuffer[o]; @@ -1021,10 +1169,17 @@ namespace SixLabors.ImageSharp.Formats.Png } else if (this.pngColorType == PngColorType.Grayscale) { - // TODO: 16 bit if (alpha.Length >= 2) { - this.intensityTrans = ReadByteLittleEndian(alpha, 0); + if (this.header.BitDepth == 16) + { + this.luminance16Trans = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(0, 2)); + } + else + { + this.luminanceTrans = ReadByteLittleEndian(alpha, 0); + } + this.hasTrans = true; } } @@ -1043,17 +1198,16 @@ namespace SixLabors.ImageSharp.Formats.Png ReadOnlySpan pal = MemoryMarshal.Cast(this.palette); var color = default(TPixel); - var rgba = default(Rgba32); - 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 = newScanline[x]; - - rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255; + rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : byte.MaxValue; rgba.Rgb = pal[index]; color.PackFromRgba32(rgba); @@ -1062,7 +1216,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - rgba.A = 255; + var rgba = new Rgba32(0, 0, 0, byte.MaxValue); for (int x = 0; x < this.header.Width; x++) { @@ -1212,6 +1366,10 @@ namespace SixLabors.ImageSharp.Formats.Png return true; } + /// + /// Validates the png chunk. + /// + /// The . private void ValidateChunk(in PngChunk chunk) { this.crc.Reset(); From 0e9efdf693ff0aed76822a04c8a04133b327b9f2 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 16 Jun 2018 01:55:25 +1000 Subject: [PATCH 15/30] Fix alpha8 conversion. --- src/ImageSharp/PixelFormats/Alpha8.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/Alpha8.cs index c8534ae22..dda7bc82b 100644 --- a/src/ImageSharp/PixelFormats/Alpha8.cs +++ b/src/ImageSharp/PixelFormats/Alpha8.cs @@ -179,6 +179,7 @@ namespace SixLabors.ImageSharp.PixelFormats dest.R = 0; dest.G = 0; dest.B = 0; + dest.A = this.PackedValue; } /// From 7ee6f7ac3f90723da2c9469da992741d8d642172 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 16 Jun 2018 09:24:03 +1000 Subject: [PATCH 16/30] Really fix Alpha conversion --- src/ImageSharp/PixelFormats/Alpha8.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/Alpha8.cs index dda7bc82b..0b16fed0a 100644 --- a/src/ImageSharp/PixelFormats/Alpha8.cs +++ b/src/ImageSharp/PixelFormats/Alpha8.cs @@ -174,13 +174,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) - { - dest.R = 0; - dest.G = 0; - dest.B = 0; - dest.A = this.PackedValue; - } + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// /// Compares an object with the packed vector. From 4baaddfd031b6a3839f5de13618b9d845c387905 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 16 Jun 2018 11:08:04 +1000 Subject: [PATCH 17/30] Add Rgb48 tests --- .../ImageSharp.Tests/PixelFormats/Alpha8Tests.cs | 16 ++++++++++++++++ .../ImageSharp.Tests/PixelFormats/Argb32Tests.cs | 16 ++++++++++++++++ .../ImageSharp.Tests/PixelFormats/Bgr24Tests.cs | 16 ++++++++++++++++ .../ImageSharp.Tests/PixelFormats/Bgr565Tests.cs | 16 ++++++++++++++++ .../ImageSharp.Tests/PixelFormats/Bgra32Tests.cs | 16 ++++++++++++++++ .../PixelFormats/Bgra4444Tests.cs | 16 ++++++++++++++++ .../PixelFormats/Bgra5551Tests.cs | 16 ++++++++++++++++ .../ImageSharp.Tests/PixelFormats/Byte4Tests.cs | 16 ++++++++++++++++ .../PixelFormats/HalfSingleTests.cs | 16 ++++++++++++++++ .../PixelFormats/HalfVector2Tests.cs | 16 ++++++++++++++++ .../PixelFormats/HalfVector4Tests.cs | 16 ++++++++++++++++ .../PixelFormats/NormalizedByte2Tests.cs | 16 ++++++++++++++++ .../PixelFormats/NormalizedByte4Tests.cs | 16 ++++++++++++++++ .../PixelFormats/NormalizedShort2Tests.cs | 16 ++++++++++++++++ .../PixelFormats/NormalizedShort4Tests.cs | 16 ++++++++++++++++ tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs | 16 ++++++++++++++++ .../ImageSharp.Tests/PixelFormats/Rgb24Tests.cs | 16 ++++++++++++++++ .../ImageSharp.Tests/PixelFormats/Rgb48Tests.cs | 16 ++++++++++++++++ .../PixelFormats/Rgba1010102Tests.cs | 16 ++++++++++++++++ .../ImageSharp.Tests/PixelFormats/Rgba32Tests.cs | 16 ++++++++++++++++ .../ImageSharp.Tests/PixelFormats/Rgba64Tests.cs | 16 ++++++++++++++++ .../PixelFormats/RgbaVectorTests.cs | 16 ++++++++++++++++ .../ImageSharp.Tests/PixelFormats/Short2Tests.cs | 16 ++++++++++++++++ .../ImageSharp.Tests/PixelFormats/Short4Tests.cs | 16 ++++++++++++++++ 24 files changed, 384 insertions(+) diff --git a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs index 39da9f538..9a29236db 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs @@ -175,6 +175,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats 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() { diff --git a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs index 79b803be8..5817b5c32 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs @@ -190,6 +190,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats 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() { diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs index bac668ebd..048a38380 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs @@ -140,6 +140,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats 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() { diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs index 39f221832..b66cac9ca 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs @@ -145,6 +145,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats 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() { diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs index 701268f5d..70f8c35df 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs @@ -147,6 +147,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats 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() { diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs index 0bb3b2919..f643d152e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs @@ -194,6 +194,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats 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() { diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs index 6ca822ed1..b6a078031 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs @@ -193,6 +193,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats 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() { diff --git a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs index 8e9ef4b3e..28555a7df 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs @@ -191,6 +191,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats 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() { diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs index ed853e6b8..3376645f3 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs @@ -142,6 +142,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats 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() { diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs index 0cdf493d6..c2a524f0d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs @@ -147,6 +147,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats 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() { diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs index 1d6b7195b..8b28dd827 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs @@ -189,6 +189,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats 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() { diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs index d727fd952..83f22e2aa 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs @@ -158,6 +158,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats 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() { diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs index 09b5b3e57..16516496f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs @@ -169,6 +169,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats 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() { diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs index 5a9d5a36e..2fb7f05ac 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs @@ -162,6 +162,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats 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() { diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs index 55e4b7d98..7dcdd9c88 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs @@ -170,6 +170,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats 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() { diff --git a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs index cc7969846..3a80c3436 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs @@ -129,6 +129,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats 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() { diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs index f86081404..d056bf30d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -140,6 +140,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats 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() { diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index 61203a12b..ae8cb968a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -149,6 +149,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats 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() { diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs index 9c28547dd..fcb3b6c7c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs @@ -179,6 +179,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats 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() { diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs index c41f075ef..4b2c18776 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs @@ -306,6 +306,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } + [Fact] + public void Rgba32_PackFromRgb48_ToRgb48() + { + // arrange + var input = default(Rgba32); + 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 Rgba32_PackFromRgba64_ToRgba64() { diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index c04352c32..12f4d7afc 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -151,6 +151,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats 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 Rgba64_PackFromRgba64_ToRgba64() { diff --git a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs index 73f2dd126..a21b647a7 100644 --- a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs @@ -127,6 +127,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(4, ordered[3]); } + [Fact] + public void RgbaVector_PackFromRgb48_ToRgb48() + { + // arrange + var input = default(RgbaVector); + 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 RgbaVector_PackFromRgba64_ToRgba64() { diff --git a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs index bfaf64204..5c75fcbbb 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs @@ -170,6 +170,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } + [Fact] + public void Short2_PackFromRgb48_ToRgb48() + { + // arrange + var input = default(Short2); + 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 Short2_PackFromRgba64_ToRgba64() { diff --git a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs index f9e2f4b58..59dc385d4 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs @@ -206,6 +206,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } + [Fact] + public void Short4_PackFromRgb48_ToRgb48() + { + // arrange + var input = default(Short4); + 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 Short4_PackFromRgba64_ToRgba64() { From f8deb06c7c3577cca8208fcebf32849c84f0c151 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 17 Jun 2018 19:47:35 +1000 Subject: [PATCH 18/30] Add pixel operation tests --- .../PixelFormats/PixelOperationsTests.cs | 137 ++++++++++++++++-- 1 file changed, 128 insertions(+), 9 deletions(-) diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 4ae11301d..167b67954 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -3,6 +3,7 @@ using System; using System.Numerics; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -203,7 +204,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromXyzBytes(int count) + public void PackFromRgb24Bytes(int count) { byte[] source = CreateByteTestData(count * 3); var expected = new TPixel[count]; @@ -224,7 +225,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void ToXyzBytes(int count) + public void ToRgb24Bytes(int count) { TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 3]; @@ -248,7 +249,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromXyzwBytes(int count) + public void PackFromRgba32Bytes(int count) { byte[] source = CreateByteTestData(count * 4); var expected = new TPixel[count]; @@ -269,7 +270,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void ToXyzwBytes(int count) + public void ToRgba32Bytes(int count) { TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 4]; @@ -294,7 +295,109 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromZyxBytes(int count) + 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.Span, 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.Span, 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.Span, 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.Span, count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromBgr24Bytes(int count) { byte[] source = CreateByteTestData(count * 3); var expected = new TPixel[count]; @@ -315,7 +418,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void ToZyxBytes(int count) + public void ToBgr24Bytes(int count) { TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 3]; @@ -339,7 +442,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromZyxwBytes(int count) + public void PackFromBgra32Bytes(int count) { byte[] source = CreateByteTestData(count * 4); var expected = new TPixel[count]; @@ -385,7 +488,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromWzyxBytes(int count) + public void PackFromArgb32Bytes(int count) { byte[] source = CreateByteTestData(count * 4); var expected = new TPixel[count]; @@ -406,7 +509,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void ToWzyxBytes(int count) + public void ToArgb32Bytes(int count) { TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 4]; @@ -557,5 +660,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats (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 bb29ff9e1a39348f1d5245a6041b3caf562f10cb Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 18 Jun 2018 01:46:08 +1000 Subject: [PATCH 19/30] Can now encode 16bit pngs. --- .../Formats/Png/IPngEncoderOptions.cs | 14 +- src/ImageSharp/Formats/Png/PngBitDepth.cs | 22 +++ src/ImageSharp/Formats/Png/PngDecoderCore.cs | 4 + src/ImageSharp/Formats/Png/PngEncoder.cs | 14 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 161 ++++++++++++++---- .../Formats/GeneralFormatTests.cs | 2 +- .../Formats/Png/PngEncoderTests.cs | 4 +- .../Tests/ReferenceCodecTests.cs | 2 +- 8 files changed, 174 insertions(+), 49 deletions(-) create mode 100644 src/ImageSharp/Formats/Png/PngBitDepth.cs diff --git a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs index 796a13a5e..3b8aea669 100644 --- a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs @@ -11,14 +11,20 @@ namespace SixLabors.ImageSharp.Formats.Png internal interface IPngEncoderOptions { /// - /// Gets the png color type + /// Gets the number of bits per sample or per palette index (not per pixel). + /// Not all values are allowed for all values. /// - PngColorType PngColorType { get; } + PngBitDepth BitDepth { get; } /// - /// Gets the png filter method. + /// Gets the color type /// - PngFilterMethod PngFilterMethod { get; } + PngColorType ColorType { get; } + + /// + /// Gets the filter method. + /// + PngFilterMethod FilterMethod { get; } /// /// Gets the compression level 1-9. diff --git a/src/ImageSharp/Formats/Png/PngBitDepth.cs b/src/ImageSharp/Formats/Png/PngBitDepth.cs new file mode 100644 index 000000000..0c22a4c91 --- /dev/null +++ b/src/ImageSharp/Formats/Png/PngBitDepth.cs @@ -0,0 +1,22 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// Note the value assignment, This will allow us to add 1, 2, and 4 bit encoding when we support it. +namespace SixLabors.ImageSharp.Formats.Png +{ + /// + /// Provides enumeration for the available PNG bit depths. + /// + public enum PngBitDepth + { + /// + /// 8 bits per sample or per palette index (not per pixel). + /// + Bit8 = 8, + + /// + /// 16 bits per sample or per palette index (not per pixel). + /// + Bit16 = 16 + } +} diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index e4e583d19..48eb54768 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -680,6 +680,8 @@ namespace SixLabors.ImageSharp.Formats.Png case PngColorType.Grayscale: int factor = 255 / ((int)Math.Pow(2, this.header.BitDepth) - 1); + + // Convert 1, 2, and 4 bit pixel data into the 8 bit equivalent. ReadOnlySpan scanline = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth); if (!this.hasTrans) @@ -896,6 +898,8 @@ namespace SixLabors.ImageSharp.Formats.Png case PngColorType.Grayscale: int factor = 255 / ((int)Math.Pow(2, this.header.BitDepth) - 1); + + // Convert 1, 2, and 4 bit pixel data into the 8 bit equivalent. ReadOnlySpan scanline = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth); if (!this.hasTrans) diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index fab1b5185..babda2eff 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -14,14 +14,20 @@ namespace SixLabors.ImageSharp.Formats.Png public sealed class PngEncoder : IImageEncoder, IPngEncoderOptions { /// - /// Gets or sets the png color type. + /// Gets or sets the number of bits per sample or per palette index (not per pixel). + /// Not all values are allowed for all values. /// - public PngColorType PngColorType { get; set; } = PngColorType.RgbWithAlpha; + public PngBitDepth BitDepth { get; set; } = PngBitDepth.Bit8; /// - /// Gets or sets the png filter method. + /// Gets or sets the color type. /// - public PngFilterMethod PngFilterMethod { get; set; } = PngFilterMethod.Adaptive; + public PngColorType ColorType { get; set; } = PngColorType.RgbWithAlpha; + + /// + /// Gets or sets the filter method. + /// + public PngFilterMethod FilterMethod { get; set; } = PngFilterMethod.Paeth; /// /// 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 bfa20fb5e..2c516b829 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -5,6 +5,8 @@ using System; using System.Buffers.Binary; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats.Png.Filters; using SixLabors.ImageSharp.Formats.Png.Zlib; @@ -41,6 +43,16 @@ namespace SixLabors.ImageSharp.Formats.Png /// private readonly Crc32 crc = new Crc32(); + /// + /// The png bit depth + /// + private readonly PngBitDepth pngBitDepth; + + /// + /// Gets or sets a value indicating whether to use 16 bit encoding for supported color types. + /// + private readonly bool use16Bit; + /// /// The png color type. /// @@ -149,8 +161,10 @@ namespace SixLabors.ImageSharp.Formats.Png public PngEncoderCore(MemoryAllocator memoryAllocator, IPngEncoderOptions options) { this.memoryAllocator = memoryAllocator; - this.pngColorType = options.PngColorType; - this.pngFilterMethod = options.PngFilterMethod; + this.pngBitDepth = options.BitDepth; + this.use16Bit = this.pngBitDepth.Equals(PngBitDepth.Bit16); + this.pngColorType = options.ColorType; + this.pngFilterMethod = options.FilterMethod; this.compressionLevel = options.CompressionLevel; this.gamma = options.Gamma; this.quantizer = options.Quantizer; @@ -197,8 +211,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - // TODO: How do we set this in the options while keeping the value inline with the PngColorType? - this.bitDepth = 8; + this.bitDepth = (byte)(this.use16Bit ? 16 : 8); } this.bytesPerPixel = this.CalculateBytesPerPixel(); @@ -206,10 +219,10 @@ namespace SixLabors.ImageSharp.Formats.Png var header = new PngHeader( width: image.Width, height: image.Height, - colorType: this.pngColorType, bitDepth: this.bitDepth, - filterMethod: 0, // None - compressionMethod: 0, + colorType: this.pngColorType, + compressionMethod: 0, // None + filterMethod: 0, interlaceMethod: 0); // TODO: Can't write interlaced yet. this.WriteHeaderChunk(stream, header); @@ -247,28 +260,62 @@ namespace SixLabors.ImageSharp.Formats.Png private void CollectGrayscaleBytes(ReadOnlySpan rowSpan) where TPixel : struct, IPixel { - byte[] rawScanlineArray = this.rawScanline.Array; - var rgba = default(Rgba32); + // Use ITU-R recommendation 709 to match libpng. + const float RX = .2126F; + const float GX = .7152F; + const float BX = .0722F; + Span rawScanlineSpan = this.rawScanline.GetSpan(); - // Copy the pixels across from the image. - // Reuse the chunk type buffer. - for (int x = 0; x < this.width; x++) + if (this.pngColorType.Equals(PngColorType.Grayscale)) { - // Convert the color to YCbCr and store the luminance - // Optionally store the original color alpha. - int offset = x * this.bytesPerPixel; - rowSpan[x].ToRgba32(ref rgba); - byte luminance = (byte)((0.299F * rgba.R) + (0.587F * rgba.G) + (0.114F * rgba.B)); - - for (int i = 0; i < this.bytesPerPixel; i++) + // 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. + if (this.use16Bit) { - if (i == 0) + // 16 bit grayscale + Rgb48 rgb = default; + for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 2) { - rawScanlineArray[offset] = luminance; + rowSpan[x].ToRgb48(ref rgb); + ushort luminance = (ushort)((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance); } - else + } + else + { + // 8 bit grayscale + Rgb24 rgb = default; + for (int x = 0; x < rowSpan.Length; x++) { - rawScanlineArray[offset + i] = rgba.A; + rowSpan[x].ToRgb24(ref rgb); + rawScanlineSpan[x] = (byte)((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)); + } + } + } + else + { + if (this.use16Bit) + { + // 16 bit grayscale + alpha + Rgba64 rgba = default; + for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 4) + { + rowSpan[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); + } + } + else + { + // 8 bit grayscale + alpha + 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; } } } @@ -282,14 +329,54 @@ namespace SixLabors.ImageSharp.Formats.Png private void CollectTPixelBytes(ReadOnlySpan rowSpan) where TPixel : struct, IPixel { - // TODO: We need to cater for 64bit mode here. - if (this.bytesPerPixel == 4) - { - PixelOperations.Instance.ToRgba32Bytes(rowSpan, this.rawScanline.GetSpan(), this.width); - } - else + Span rawScanlineSpan = this.rawScanline.GetSpan(); + + switch (this.bytesPerPixel) { - PixelOperations.Instance.ToRgb24Bytes(rowSpan, this.rawScanline.GetSpan(), this.width); + case 4: + { + // 8 bit Rgba + PixelOperations.Instance.ToRgba32Bytes(rowSpan, rawScanlineSpan, this.width); + break; + } + + case 3: + { + // 8 bit Rgb + PixelOperations.Instance.ToRgb24Bytes(rowSpan, rawScanlineSpan, this.width); + break; + } + + case 8: + { + // 16 bit Rgba + Rgba64 rgba = default; + for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 8) + { + rowSpan[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); + } + + break; + } + + default: + { + // 16 bit Rgb + Rgb48 rgb = default; + for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 6) + { + rowSpan[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); + } + + break; + } } } @@ -367,6 +454,9 @@ namespace SixLabors.ImageSharp.Formats.Png // early on which shaves a couple of milliseconds off the processing time. UpFilter.Encode(scanSpan, prevSpan, this.up.GetSpan(), out int currentSum); + // TODO: PERF.. We should be breaking out of the encoding for each line as soon as we hit the sum. + // That way the above comment would actually be true. It used to be anyway... + // If we could use SIMD for none branching filters we could really speed it up. int lowestSum = currentSum; IManagedByteBuffer actualResult = this.up; @@ -402,26 +492,23 @@ namespace SixLabors.ImageSharp.Formats.Png /// The private int CalculateBytesPerPixel() { - // TODO: Cater for 64 bit here and below switch (this.pngColorType) { case PngColorType.Grayscale: - return 1; + return this.use16Bit ? 2 : 1; case PngColorType.GrayscaleWithAlpha: - return 2; + return this.use16Bit ? 4 : 2; case PngColorType.Palette: return 1; case PngColorType.Rgb: - return 3; + return this.use16Bit ? 6 : 3; // PngColorType.RgbWithAlpha - // TODO: Maybe figure out a way to detect if there are any transparent - // pixels and encode RGB if none. default: - return 4; + return this.use16Bit ? 8 : 4; } } diff --git a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs index 084b93b39..97b498ee4 100644 --- a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs +++ b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs @@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.Tests using (Image image = provider.GetImage()) { image.Mutate(c => c.Quantize(quantizer)); - image.DebugSave(provider, new PngEncoder() { PngColorType = PngColorType.Palette }, testOutputDetails: quantizerName); + image.DebugSave(provider, new PngEncoder() { ColorType = PngColorType.Palette }, testOutputDetails: quantizerName); } provider.Configuration.MemoryAllocator.ReleaseRetainedResources(); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 11124ad03..eb046165d 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -130,8 +130,8 @@ namespace SixLabors.ImageSharp.Tests var encoder = new PngEncoder { - PngColorType = pngColorType, - PngFilterMethod = pngFilterMethod, + ColorType = pngColorType, + FilterMethod = pngFilterMethod, CompressionLevel = compressionLevel, Quantizer = new WuQuantizer(paletteSize) }; diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceCodecTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceCodecTests.cs index ee398c87b..520b8d93f 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceCodecTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceCodecTests.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Tests sourceImage.Mutate(c => c.MakeOpaque()); } - var encoder = new PngEncoder() { PngColorType = pngColorType }; + var encoder = new PngEncoder() { ColorType = pngColorType }; return provider.Utility.SaveTestOutputFile(sourceImage, "png", encoder); } } From 84926561b1f8132987933e680f40e75788544cd4 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 18 Jun 2018 01:47:57 +1000 Subject: [PATCH 20/30] Update submodule from master. --- tests/Images/External | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Images/External b/tests/Images/External index eb40b3c03..0e6407be7 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit eb40b3c039dd8c8ca448cb8073a59ca178901e9f +Subproject commit 0e6407be7081341526f815a4d70e7912db276a98 From 8628aaa8a6811483fa2659379749aea6bc030166 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 18 Jun 2018 14:45:35 +1000 Subject: [PATCH 21/30] Add 16bit decoder tests. --- .../Formats/Png/PngConfigurationModule.cs | 8 +- .../Formats/Png/PngDecoderTests.cs | 143 +++++++++++++----- tests/ImageSharp.Tests/TestFile.cs | 5 +- tests/ImageSharp.Tests/TestImages.cs | 6 +- .../ImageProviders/TestPatternProvider.cs | 20 +-- .../TestUtilities/PixelTypes.cs | 2 + .../TestUtilities/TestEnvironment.Formats.cs | 13 +- tests/Images/Input/Png/gray-16-tRNS.png | Bin 0 -> 684 bytes tests/Images/Input/Png/gray-16.png | Bin 0 -> 684 bytes tests/Images/Input/Png/gray-alpha-16.png | Bin 0 -> 859 bytes tests/Images/Input/Png/rgb-16-alpha.png | Bin 0 -> 1377 bytes 11 files changed, 133 insertions(+), 64 deletions(-) create mode 100644 tests/Images/Input/Png/gray-16-tRNS.png create mode 100644 tests/Images/Input/Png/gray-16.png create mode 100644 tests/Images/Input/Png/gray-alpha-16.png create mode 100644 tests/Images/Input/Png/rgb-16-alpha.png diff --git a/src/ImageSharp/Formats/Png/PngConfigurationModule.cs b/src/ImageSharp/Formats/Png/PngConfigurationModule.cs index 0036280a8..64dad23bc 100644 --- a/src/ImageSharp/Formats/Png/PngConfigurationModule.cs +++ b/src/ImageSharp/Formats/Png/PngConfigurationModule.cs @@ -9,11 +9,11 @@ namespace SixLabors.ImageSharp.Formats.Png public sealed class PngConfigurationModule : IConfigurationModule { /// - public void Configure(Configuration config) + public void Configure(Configuration configuration) { - config.ImageFormatsManager.SetEncoder(ImageFormats.Png, new PngEncoder()); - config.ImageFormatsManager.SetDecoder(ImageFormats.Png, new PngDecoder()); - config.ImageFormatsManager.AddImageFormatDetector(new PngImageFormatDetector()); + configuration.ImageFormatsManager.SetEncoder(ImageFormats.Png, new PngEncoder()); + configuration.ImageFormatsManager.SetDecoder(ImageFormats.Png, new PngDecoder()); + configuration.ImageFormatsManager.AddImageFormatDetector(new PngImageFormatDetector()); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 02fcd1643..348b3b185 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -21,65 +21,83 @@ namespace SixLabors.ImageSharp.Tests private const PixelTypes PixelTypes = Tests.PixelTypes.Rgba32 | Tests.PixelTypes.RgbaVector | Tests.PixelTypes.Argb32; // Contains the png marker, IHDR and pHYs chunks of a 1x1 pixel 32bit png 1 a single black pixel. - private static byte[] raw1x1PngIHDRAndpHYs = + private static readonly byte[] raw1x1PngIHDRAndpHYs = { // PNG Identifier 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, - + // IHDR 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00, // IHDR CRC - 0x90, 0x77, 0x53, 0xDE, + 0x90, 0x77, 0x53, 0xDE, // pHYS - 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0E, 0xC3, 0x00, 0x00, 0x0E, 0xC3, 0x01, + 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0E, 0xC3, 0x00, 0x00, 0x0E, 0xC3, 0x01, // pHYS CRC 0xC7, 0x6F, 0xA8, 0x64 }; // Contains the png marker, IDAT and IEND chunks of a 1x1 pixel 32bit png 1 a single black pixel. - private static byte[] raw1x1PngIDATAndIEND = + private static readonly byte[] raw1x1PngIDATAndIEND = { // IDAT 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41, 0x54, 0x18, 0x57, 0x63, 0x60, 0x60, 0x60, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x01, + 0x00, 0x04, 0x00, 0x01, + // IDAT CRC - 0x5C, 0xCD, 0xFF, 0x69, + 0x5C, 0xCD, 0xFF, 0x69, // IEND 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, - 0x4E, 0x44, + 0x4E, 0x44, + // IEND CRC 0xAE, 0x42, 0x60, 0x82 }; public static readonly string[] CommonTestImages = - { - TestImages.Png.Splash, - TestImages.Png.Indexed, - TestImages.Png.FilterVar, - TestImages.Png.Bad.ChunkLength1, - TestImages.Png.Bad.CorruptedChunk, + { + TestImages.Png.Splash, + TestImages.Png.Indexed, + TestImages.Png.FilterVar, + TestImages.Png.Bad.ChunkLength1, + TestImages.Png.Bad.CorruptedChunk, + + TestImages.Png.VimImage1, + TestImages.Png.VersioningImage1, + TestImages.Png.VersioningImage2, + + TestImages.Png.SnakeGame, + TestImages.Png.Banner7Adam7InterlaceMode, + TestImages.Png.Banner8Index, + + TestImages.Png.Bad.ChunkLength2, + TestImages.Png.VimImage2, + }; - TestImages.Png.VimImage1, - TestImages.Png.VersioningImage1, - TestImages.Png.VersioningImage2, - TestImages.Png.SnakeGame, - TestImages.Png.Banner7Adam7InterlaceMode, - TestImages.Png.Banner8Index, + public static readonly string[] TestImages48Bpp = + { + TestImages.Png.Rgb48Bpp, + TestImages.Png.Rgb48BppInterlaced + }; - TestImages.Png.Bad.ChunkLength2, - TestImages.Png.VimImage2, - }; + public static readonly string[] TestImages64Bpp = +{ + TestImages.Png.Rgba64Bpp, + }; + public static readonly string[] TestImagesGray16Bit = + { + TestImages.Png.Gray16Bit, + }; - public static readonly string[] TestImages48Bpp = - { - TestImages.Png.Rgb48Bpp, - TestImages.Png.Rgb48BppInterlaced - }; + public static readonly string[] TestImagesGrayAlpha16Bit = + { + TestImages.Png.GrayAlpha16Bit, + TestImages.Png.GrayTrns16Bit + }; // This is a workaround for Mono-s decoder being incompatible with ours and GDI+. // We shouldn't mix these with the Interleaved cases (which are also failing with Mono System.Drawing). Let's go AAA! @@ -142,20 +160,66 @@ namespace SixLabors.ImageSharp.Tests } } - // TODO: We need to decode these into Rgba64 properly, and do 'CompareToOriginal' in a Rgba64 mode! (See #285) - [Theory(Skip = "Skipped for now until we can update the reference images from libpng samples.")] - [WithFileCollection(nameof(TestImages48Bpp), PixelTypes.Rgba32)] + [Theory] + [WithFileCollection(nameof(TestImages48Bpp), PixelTypes.Rgb48)] public void Decode_48Bpp(TestImageProvider provider) where TPixel : struct, IPixel { using (Image image = provider.GetImage(new PngDecoder())) { - image.DebugSave(provider); + var encoder = new PngEncoder { ColorType = PngColorType.Rgb, BitDepth = PngBitDepth.Bit16 }; - // Workaround a bug in mono-s System.Drawing PNG decoder. It can't deal with 48Bpp png-s :( - if (!TestEnvironment.IsLinux && !TestEnvironment.IsMono) + if (!SkipVerification(provider)) { - image.CompareToOriginal(provider, ImageComparer.Exact); + image.VerifyEncoder(provider, "png", null, encoder, customComparer: ImageComparer.Exact); + } + } + } + + [Theory] + [WithFileCollection(nameof(TestImages64Bpp), PixelTypes.Rgba64)] + public void Decode_64Bpp(TestImageProvider provider) + where TPixel : struct, IPixel + { + using (Image image = provider.GetImage(new PngDecoder())) + { + var encoder = new PngEncoder { ColorType = PngColorType.RgbWithAlpha, BitDepth = PngBitDepth.Bit16 }; + + if (!SkipVerification(provider)) + { + image.VerifyEncoder(provider, "png", null, encoder, customComparer: ImageComparer.Exact); + } + } + } + + [Theory] + [WithFileCollection(nameof(TestImagesGray16Bit), PixelTypes.Rgb48)] + public void Decode_Gray16Bit(TestImageProvider provider) + where TPixel : struct, IPixel + { + using (Image image = provider.GetImage(new PngDecoder())) + { + var encoder = new PngEncoder { ColorType = PngColorType.Grayscale, BitDepth = PngBitDepth.Bit16 }; + + if (!SkipVerification(provider)) + { + image.VerifyEncoder(provider, "png", null, encoder, customComparer: ImageComparer.Exact); + } + } + } + + [Theory] + [WithFileCollection(nameof(TestImagesGrayAlpha16Bit), PixelTypes.Rgba64)] + public void Decode_GrayAlpha16Bit(TestImageProvider provider) + where TPixel : struct, IPixel + { + using (Image image = provider.GetImage(new PngDecoder())) + { + var encoder = new PngEncoder { ColorType = PngColorType.GrayscaleWithAlpha, BitDepth = PngBitDepth.Bit16 }; + + if (!SkipVerification(provider)) + { + image.VerifyEncoder(provider, "png", null, encoder, customComparer: ImageComparer.Exact); } } } @@ -233,7 +297,7 @@ namespace SixLabors.ImageSharp.Tests [InlineData(TestImages.Png.Rgb48BppInterlaced, 48)] public void DetectPixelSize(string imagePath, int expectedPixelSize) { - TestFile testFile = TestFile.Create(imagePath); + var testFile = TestFile.Create(imagePath); using (var stream = new MemoryStream(testFile.Bytes, false)) { Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType?.BitsPerPixel); @@ -257,10 +321,7 @@ namespace SixLabors.ImageSharp.Tests var decoder = new PngDecoder(); - ImageFormatException exception = Assert.Throws(() => - { - decoder.Decode(null, memStream); - }); + ImageFormatException exception = Assert.Throws(() => decoder.Decode(null, memStream)); Assert.Equal($"CRC Error. PNG {chunkName} chunk is corrupt!", exception.Message); } diff --git a/tests/ImageSharp.Tests/TestFile.cs b/tests/ImageSharp.Tests/TestFile.cs index b736dce20..089249e21 100644 --- a/tests/ImageSharp.Tests/TestFile.cs +++ b/tests/ImageSharp.Tests/TestFile.cs @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Tests /// // ReSharper disable once InconsistentNaming private static readonly Lazy inputImagesDirectory = new Lazy(() => TestEnvironment.InputImagesDirectoryFullPath); - + /// /// The image (lazy initialized value) /// @@ -74,9 +74,10 @@ namespace SixLabors.ImageSharp.Tests private Image Image => this.image ?? (this.image = ImageSharp.Image.Load(this.Bytes)); /// + /// Gets the input image directory. /// private static string InputImagesDirectory => inputImagesDirectory.Value; - + /// /// Gets the full qualified path to the input test file. /// diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index d261f9497..d965b01d7 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -27,7 +27,11 @@ namespace SixLabors.ImageSharp.Tests public const string Palette8Bpp = "Png/palette-8bpp.png"; public const string Bpp1 = "Png/bpp1.png"; public const string Gray4Bpp = "Png/gray_4bpp.png"; + public const string Gray16Bit = "Png/gray-16.png"; + public const string GrayAlpha16Bit = "Png/gray-alpha-16.png"; + public const string GrayTrns16Bit = "Png/gray-16-tRNS.png"; public const string Rgb48Bpp = "Png/rgb-48bpp.png"; + public const string Rgba64Bpp = "Png/rgb-16-alpha.png"; public const string CalliphoraPartial = "Png/CalliphoraPartial.png"; public const string CalliphoraPartialGrayscale = "Png/CalliphoraPartialGrayscale.png"; public const string Bike = "Png/Bike.png"; @@ -126,7 +130,7 @@ namespace SixLabors.ImageSharp.Tests }; } - public class Issues + public static class Issues { public const string CriticalEOF214 = "Jpg/issues/Issue214-CriticalEOF.jpg"; public const string MissingFF00ProgressiveGirl159 = "Jpg/issues/Issue159-MissingFF00-Progressive-Girl.jpg"; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs index 4dcfcd4b7..9de791ab6 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs @@ -80,11 +80,12 @@ namespace SixLabors.ImageSharp.Tests stride = 1; } - TPixel[] c = { - NamedColors.HotPink, - NamedColors.Blue - }; - + TPixel[] c = + { + NamedColors.HotPink, + NamedColors.Blue + }; + for (int y = top; y < bottom; y++) { int p = 0; @@ -112,10 +113,11 @@ namespace SixLabors.ImageSharp.Tests int top = 0; int bottom = pixels.Height / 2; int stride = pixels.Width / 6; - TPixel[] c = { - NamedColors.Black, - NamedColors.White - }; + TPixel[] c = + { + NamedColors.Black, + NamedColors.White + }; int p = 0; for (int y = top; y < bottom; y++) diff --git a/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs b/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs index a8f7acb40..a051e577d 100644 --- a/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs +++ b/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs @@ -56,6 +56,8 @@ namespace SixLabors.ImageSharp.Tests Bgra32 = 1 << 20, + Rgb48 = 1 << 21, + // TODO: Add multi-flag entries by rules defined in PackedPixelConverterHelper // "All" is handled as a separate, individual case instead of using bitwise OR diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs index 6bebf3887..f62237936 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Tests private static Lazy configuration = new Lazy(CreateDefaultConfiguration); internal static Configuration Configuration => configuration.Value; - + internal static IImageDecoder GetReferenceDecoder(string filePath) { IImageFormat format = GetImageFormat(filePath); @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Tests internal static IImageFormat GetImageFormat(string filePath) { string extension = Path.GetExtension(filePath); - + IImageFormat format = Configuration.ImageFormatsManager.FindFormatByFileExtension(extension); return format; } @@ -60,11 +60,10 @@ namespace SixLabors.ImageSharp.Tests if (!IsLinux) { - configuration.ConfigureCodecs( - ImageFormats.Png, - SystemDrawingReferenceDecoder.Instance, - SystemDrawingReferenceEncoder.Png, - new PngImageFormatDetector()); + // System.Drawing on Windows can decode 48bit and 64bit pngs but + // it doesn't preserve the accuracy we require for comparison. + // This makes CompareToOriginal method non-useful. + configuration.Configure(new PngConfigurationModule()); configuration.ConfigureCodecs( ImageFormats.Bmp, diff --git a/tests/Images/Input/Png/gray-16-tRNS.png b/tests/Images/Input/Png/gray-16-tRNS.png new file mode 100644 index 0000000000000000000000000000000000000000..4826d61eb7fab6977de0135762596f6220847a51 GIT binary patch literal 684 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K583ceNgJ!4pPavgJ;u=xnoL^8`l$oAU!mv`o z$iUE82S}JIc;#p0DL9wrQ)?6_t8Wt(r^S91+lJYzG)57?=|n qcp4Z7m@_CG0SSfy4hgU$t}`7;V&*H`p}d0u2s~Z=T-G@yGywqIAfV*{ literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Png/gray-16.png b/tests/Images/Input/Png/gray-16.png new file mode 100644 index 0000000000000000000000000000000000000000..4826d61eb7fab6977de0135762596f6220847a51 GIT binary patch literal 684 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K583ceNgJ!4pPavgJ;u=xnoL^8`l$oAU!mv`o z$iUE82S}JIc;#p0DL9wrQ)?6_t8Wt(r^S91+lJYzG)57?=|n qcp4Z7m@_CG0SSfy4hgU$t}`7;V&*H`p}d0u2s~Z=T-G@yGywqIAfV*{ literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Png/gray-alpha-16.png b/tests/Images/Input/Png/gray-alpha-16.png new file mode 100644 index 0000000000000000000000000000000000000000..689879737fc6df3cb65e3b210067b9ddbac53a38 GIT binary patch literal 859 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K583b5>)Uwxm)&VJ<64!_l=lp`oqRjM+5{8uu zMh1q)IzYly!7D!_PriCniktMc5r zI%d^st;i|py?3d@n#R&Q*X742 zEc08>d`5*qfuRAYhk=7?42}k22T)M5FbFVEiy^?EPGwgr0R8JnWmh@?{VT&r&9DST h4%IzQEh9fXVBe?mZ{fld>tz^#z|+;wWt~$(69BnNk^TSx literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Png/rgb-16-alpha.png b/tests/Images/Input/Png/rgb-16-alpha.png new file mode 100644 index 0000000000000000000000000000000000000000..59262397eb5b4adc3e833e066f0cc19323a53d88 GIT binary patch literal 1377 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K583fpX6wjj)RUoBP;u=xnoL^8`l$oAU!mv`o z$iUE82S}JIc;#p0DL9wrQ)?6_t8Wt(r^S9 KpUXO@geCyOk#FVz literal 0 HcmV?d00001 From 49a574537f8a8037881aa6cc98f6ebfc8b3d2320 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 18 Jun 2018 16:40:29 +1000 Subject: [PATCH 22/30] All tests now pass --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 38 +++++++++++++++---- .../Drawing/Text/DrawTextOnImageTests.cs | 13 ++++--- .../Tests/TestEnvironmentTests.cs | 4 +- tests/Images/External | 2 +- 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 2c516b829..d816a0fd2 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -5,8 +5,6 @@ using System; using System.Buffers.Binary; using System.IO; using System.Linq; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats.Png.Filters; using SixLabors.ImageSharp.Formats.Png.Zlib; @@ -394,7 +392,6 @@ namespace SixLabors.ImageSharp.Formats.Png switch (this.pngColorType) { case PngColorType.Palette: - // TODO: Use Span copy! Buffer.BlockCopy(this.palettePixelData, row * this.rawScanline.Length(), this.rawScanline.Array, 0, this.rawScanline.Length()); break; case PngColorType.Grayscale: @@ -646,12 +643,37 @@ namespace SixLabors.ImageSharp.Formats.Png this.rawScanline = this.memoryAllocator.AllocateCleanManagedByteBuffer(this.bytesPerScanline); this.result = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength); - if (this.pngColorType != PngColorType.Palette) + switch (this.pngFilterMethod) { - this.sub = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength); - this.up = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength); - this.average = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength); - this.paeth = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength); + case PngFilterMethod.None: + break; + + case PngFilterMethod.Sub: + + this.sub = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength); + break; + + case PngFilterMethod.Up: + + this.up = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength); + break; + + case PngFilterMethod.Average: + + this.average = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength); + break; + + case PngFilterMethod.Paeth: + + this.paeth = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength); + break; + case PngFilterMethod.Adaptive: + + this.sub = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength); + this.up = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength); + this.average = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength); + this.paeth = this.memoryAllocator.AllocateCleanManagedByteBuffer(resultLength); + break; } byte[] buffer; diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs index a9c7a6ebb..13e0bbadf 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs @@ -84,12 +84,13 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text } var textOptions = new TextGraphicsOptions - { - Antialias = true, - ApplyKerning = true, - VerticalAlignment = VerticalAlignment.Top, - HorizontalAlignment = HorizontalAlignment.Left, - }; + { + Antialias = true, + ApplyKerning = true, + VerticalAlignment = VerticalAlignment.Top, + HorizontalAlignment = HorizontalAlignment.Left, + }; + TPixel color = NamedColors.Black; provider.VerifyOperation( diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs index 9db55281e..40338e859 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.Tests } [Theory] - [InlineData("lol/foo.png", typeof(SystemDrawingReferenceEncoder))] + [InlineData("lol/foo.png", typeof(PngEncoder))] [InlineData("lol/Rofl.bmp", typeof(SystemDrawingReferenceEncoder))] [InlineData("lol/Baz.JPG", typeof(JpegEncoder))] [InlineData("lol/Baz.gif", typeof(GifEncoder))] @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Tests } [Theory] - [InlineData("lol/foo.png", typeof(SystemDrawingReferenceDecoder))] + [InlineData("lol/foo.png", typeof(PngDecoder))] [InlineData("lol/Rofl.bmp", typeof(SystemDrawingReferenceDecoder))] [InlineData("lol/Baz.JPG", typeof(JpegDecoder))] [InlineData("lol/Baz.gif", typeof(GifDecoder))] diff --git a/tests/Images/External b/tests/Images/External index 0e6407be7..147306294 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 0e6407be7081341526f815a4d70e7912db276a98 +Subproject commit 147306294437dc03f6e640f5db2dcd496a43ced7 From 1d8c2398ca798243965c089b272a2f21e90ae958 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 18 Jun 2018 17:59:16 +1000 Subject: [PATCH 23/30] Remove allocation when upscaling. --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 296 +++++++++--------- .../Formats/Png/PngDecoderTests.cs | 5 +- 2 files changed, 152 insertions(+), 149 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 48eb54768..04d4f057c 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -341,25 +341,36 @@ namespace SixLabors.ImageSharp.Formats.Png } /// - /// Converts a byte array to a new array where each value in the original array is represented by the specified number of bits. + /// Reads the least significant bits from the byte pair with the others set to 0. + /// + /// The source buffer + /// THe offset + /// The + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte ReadByteLittleEndian(ReadOnlySpan buffer, int offset) + { + 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 + /// specified number of bits. /// /// The bytes to convert from. Cannot be empty. /// The number of bytes per scanline /// The number of bits per value. + /// The new array. /// The resulting array. - /// is less than or equals than zero. - private static ReadOnlySpan ToArrayByBitsLength(ReadOnlySpan source, int bytesPerScanline, int bits) + private bool TryScaleUpTo8BitArray(ReadOnlySpan source, int bytesPerScanline, int bits, out IManagedByteBuffer buffer) { - Guard.MustBeGreaterThan(source.Length, 0, nameof(source)); - Guard.MustBeGreaterThan(bits, 0, nameof(bits)); - if (bits >= 8) { - return source; + buffer = null; + return false; } - // TODO: We should be pooling this. - byte[] result = new byte[bytesPerScanline * 8 / bits]; + buffer = this.MemoryAllocator.AllocateCleanManagedByteBuffer(bytesPerScanline * 8 / bits); + byte[] result = buffer.Array; int mask = 0xFF >> (8 - bits); int resultOffset = 0; @@ -369,26 +380,13 @@ namespace SixLabors.ImageSharp.Formats.Png for (int shift = 0; shift < 8; shift += bits) { int colorIndex = (b >> (8 - bits - shift)) & mask; - result[resultOffset] = (byte)colorIndex; resultOffset++; } } - return result; - } - - /// - /// Reads the least significant bits from the byte pair with the others set to 0. - /// - /// The source buffer - /// THe offset - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static byte ReadByteLittleEndian(ReadOnlySpan buffer, int offset) - { - return (byte)(((buffer[offset] & 0xFF) << 16) | (buffer[offset + 1] & 0xFF)); + return true; } /// @@ -669,11 +667,16 @@ namespace SixLabors.ImageSharp.Formats.Png private void ProcessDefilteredScanline(ReadOnlySpan defilteredScanline, ImageFrame pixels) where TPixel : struct, IPixel { - var color = default(TPixel); + TPixel pixel = default; Span rowSpan = pixels.GetPixelRowSpan(this.currentRow); // Trim the first marker byte from the buffer - ReadOnlySpan scanlineBuffer = defilteredScanline.Slice(1, defilteredScanline.Length - 1); + 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) + ? buffer.GetSpan() + : trimmed; switch (this.pngColorType) { @@ -681,9 +684,6 @@ namespace SixLabors.ImageSharp.Formats.Png int factor = 255 / ((int)Math.Pow(2, this.header.BitDepth) - 1); - // Convert 1, 2, and 4 bit pixel data into the 8 bit equivalent. - ReadOnlySpan scanline = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth); - if (!this.hasTrans) { if (this.header.BitDepth == 16) @@ -691,12 +691,12 @@ namespace SixLabors.ImageSharp.Formats.Png Rgb48 rgb48 = default; for (int x = 0, o = 0; x < this.header.Width; x++, o += 2) { - ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2)); + ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); rgb48.R = luminance; rgb48.G = luminance; rgb48.B = luminance; - color.PackFromRgb48(rgb48); - rowSpan[x] = color; + pixel.PackFromRgb48(rgb48); + rowSpan[x] = pixel; } } else @@ -705,12 +705,12 @@ 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)(scanline[x] * factor); + byte luminance = (byte)(scanlineSpan[x] * factor); rgba32.R = luminance; rgba32.G = luminance; rgba32.B = luminance; - color.PackFromRgba32(rgba32); - rowSpan[x] = color; + pixel.PackFromRgba32(rgba32); + rowSpan[x] = pixel; } } } @@ -721,14 +721,14 @@ namespace SixLabors.ImageSharp.Formats.Png Rgba64 rgba64 = default; for (int x = 0, o = 0; x < this.header.Width; x++, o += 2) { - ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(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; - color.PackFromRgba64(rgba64); - rowSpan[x] = color; + pixel.PackFromRgba64(rgba64); + rowSpan[x] = pixel; } } else @@ -736,14 +736,14 @@ namespace SixLabors.ImageSharp.Formats.Png Rgba32 rgba32 = default; for (int x = 0; x < this.header.Width; x++) { - byte luminance = (byte)(scanline[x] * factor); + byte luminance = (byte)(scanlineSpan[x] * factor); rgba32.R = luminance; rgba32.G = luminance; rgba32.B = luminance; rgba32.A = luminance.Equals(this.luminanceTrans) ? byte.MinValue : byte.MaxValue; - color.PackFromRgba32(rgba32); - rowSpan[x] = color; + pixel.PackFromRgba32(rgba32); + rowSpan[x] = pixel; } } } @@ -757,15 +757,15 @@ namespace SixLabors.ImageSharp.Formats.Png Rgba64 rgba64 = default; for (int x = 0, o = 0; x < this.header.Width; x++, o += 4) { - ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2)); - ushort alpha = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2)); + 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; - color.PackFromRgba64(rgba64); - rowSpan[x] = color; + pixel.PackFromRgba64(rgba64); + rowSpan[x] = pixel; } } else @@ -774,16 +774,16 @@ namespace SixLabors.ImageSharp.Formats.Png for (int x = 0; x < this.header.Width; x++) { int offset = x * this.bytesPerPixel; - byte luminance = scanlineBuffer[offset]; - byte alpha = scanlineBuffer[offset + this.bytesPerSample]; + byte luminance = scanlineSpan[offset]; + byte alpha = scanlineSpan[offset + this.bytesPerSample]; rgba32.R = luminance; rgba32.G = luminance; rgba32.B = luminance; rgba32.A = alpha; - color.PackFromRgba32(rgba32); - rowSpan[x] = color; + pixel.PackFromRgba32(rgba32); + rowSpan[x] = pixel; } } @@ -791,7 +791,7 @@ namespace SixLabors.ImageSharp.Formats.Png case PngColorType.Palette: - this.ProcessScanlineFromPalette(scanlineBuffer, rowSpan); + this.ProcessScanlineFromPalette(scanlineSpan, rowSpan); break; @@ -804,16 +804,16 @@ namespace SixLabors.ImageSharp.Formats.Png Rgb48 rgb48 = default; for (int x = 0, o = 0; x < this.header.Width; x++, o += 6) { - rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2)); - rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2)); - rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 4, 2)); - color.PackFromRgb48(rgb48); - rowSpan[x] = color; + 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; } } else { - PixelOperations.Instance.PackFromRgb24Bytes(scanlineBuffer, rowSpan, this.header.Width); + PixelOperations.Instance.PackFromRgb24Bytes(scanlineSpan, rowSpan, this.header.Width); } } else @@ -824,20 +824,20 @@ namespace SixLabors.ImageSharp.Formats.Png Rgba64 rgba64 = default; for (int x = 0, o = 0; x < this.header.Width; x++, o += 6) { - rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2)); - rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2)); - rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 4, 2)); + 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; - color.PackFromRgba64(rgba64); - rowSpan[x] = color; + pixel.PackFromRgba64(rgba64); + rowSpan[x] = pixel; } } else { - ReadOnlySpan rgb24Span = MemoryMarshal.Cast(scanlineBuffer); + ReadOnlySpan rgb24Span = MemoryMarshal.Cast(scanlineSpan); for (int x = 0; x < this.header.Width; x++) { ref readonly Rgb24 rgb24 = ref rgb24Span[x]; @@ -845,8 +845,8 @@ namespace SixLabors.ImageSharp.Formats.Png rgba32.Rgb = rgb24; rgba32.A = rgb24.Equals(this.rgb24Trans) ? byte.MinValue : byte.MaxValue; - color.PackFromRgba32(rgba32); - rowSpan[x] = color; + pixel.PackFromRgba32(rgba32); + rowSpan[x] = pixel; } } } @@ -860,21 +860,23 @@ namespace SixLabors.ImageSharp.Formats.Png Rgba64 rgba64 = default; for (int x = 0, o = 0; x < this.header.Width; x++, o += 8) { - rgba64.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2)); - rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2)); - rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 4, 2)); - rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 6, 2)); - color.PackFromRgba64(rgba64); - rowSpan[x] = color; + 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); + rowSpan[x] = pixel; } } else { - PixelOperations.Instance.PackFromRgba32Bytes(scanlineBuffer, rowSpan, this.header.Width); + PixelOperations.Instance.PackFromRgba32Bytes(scanlineSpan, rowSpan, this.header.Width); } break; } + + buffer?.Dispose(); } /// @@ -888,10 +890,15 @@ namespace SixLabors.ImageSharp.Formats.Png private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defilteredScanline, Span rowSpan, int pixelOffset = 0, int increment = 1) where TPixel : struct, IPixel { - var color = default(TPixel); + TPixel pixel = default; // Trim the first marker byte from the buffer - ReadOnlySpan scanlineBuffer = defilteredScanline.Slice(1, defilteredScanline.Length - 1); + 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) + ? buffer.GetSpan() + : trimmed; switch (this.pngColorType) { @@ -899,9 +906,6 @@ namespace SixLabors.ImageSharp.Formats.Png int factor = 255 / ((int)Math.Pow(2, this.header.BitDepth) - 1); - // Convert 1, 2, and 4 bit pixel data into the 8 bit equivalent. - ReadOnlySpan scanline = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth); - if (!this.hasTrans) { if (this.header.BitDepth == 16) @@ -909,13 +913,13 @@ namespace SixLabors.ImageSharp.Formats.Png Rgb48 rgb48 = default; for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 2) { - ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2)); + ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); rgb48.R = luminance; rgb48.G = luminance; rgb48.B = luminance; - color.PackFromRgb48(rgb48); - rowSpan[x] = color; + pixel.PackFromRgb48(rgb48); + rowSpan[x] = pixel; } } else @@ -924,13 +928,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)(scanline[o] * factor); + byte luminance = (byte)(scanlineSpan[o] * factor); rgba32.R = luminance; rgba32.G = luminance; rgba32.B = luminance; - color.PackFromRgba32(rgba32); - rowSpan[x] = color; + pixel.PackFromRgba32(rgba32); + rowSpan[x] = pixel; } } } @@ -941,14 +945,14 @@ namespace SixLabors.ImageSharp.Formats.Png Rgba64 rgba64 = default; for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 2) { - ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(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; - color.PackFromRgba64(rgba64); - rowSpan[x] = color; + pixel.PackFromRgba64(rgba64); + rowSpan[x] = pixel; } } else @@ -956,14 +960,14 @@ namespace SixLabors.ImageSharp.Formats.Png Rgba32 rgba32 = default; for (int x = pixelOffset; x < this.header.Width; x += increment) { - byte luminance = (byte)(scanline[x] * factor); + byte luminance = (byte)(scanlineSpan[x] * factor); rgba32.R = luminance; rgba32.G = luminance; rgba32.B = luminance; rgba32.A = luminance.Equals(this.luminanceTrans) ? byte.MinValue : byte.MaxValue; - color.PackFromRgba32(rgba32); - rowSpan[x] = color; + pixel.PackFromRgba32(rgba32); + rowSpan[x] = pixel; } } } @@ -977,15 +981,15 @@ namespace SixLabors.ImageSharp.Formats.Png Rgba64 rgba64 = default; for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 4) { - ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2)); - ushort alpha = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2)); + 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; - color.PackFromRgba64(rgba64); - rowSpan[x] = color; + pixel.PackFromRgba64(rgba64); + rowSpan[x] = pixel; } } else @@ -994,15 +998,15 @@ namespace SixLabors.ImageSharp.Formats.Png for (int x = pixelOffset; x < this.header.Width; x += increment) { int offset = x * this.bytesPerPixel; - byte luminance = scanlineBuffer[offset]; - byte alpha = scanlineBuffer[offset + this.bytesPerSample]; + byte luminance = scanlineSpan[offset]; + byte alpha = scanlineSpan[offset + this.bytesPerSample]; rgba32.R = luminance; rgba32.G = luminance; rgba32.B = luminance; rgba32.A = alpha; - color.PackFromRgba32(rgba32); - rowSpan[x] = color; + pixel.PackFromRgba32(rgba32); + rowSpan[x] = pixel; } } @@ -1010,8 +1014,7 @@ namespace SixLabors.ImageSharp.Formats.Png case PngColorType.Palette: - ReadOnlySpan newScanline = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth); - Span pal = MemoryMarshal.Cast(this.palette); + Span palettePixels = MemoryMarshal.Cast(this.palette); if (this.paletteAlpha?.Length > 0) { @@ -1020,12 +1023,12 @@ namespace SixLabors.ImageSharp.Formats.Png Rgba32 rgba = default; for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++) { - int index = newScanline[o]; + int index = scanlineSpan[o]; rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : byte.MaxValue; - rgba.Rgb = pal[index]; + rgba.Rgb = palettePixels[index]; - color.PackFromRgba32(rgba); - rowSpan[x] = color; + pixel.PackFromRgba32(rgba); + rowSpan[x] = pixel; } } else @@ -1033,11 +1036,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 = newScanline[o]; - rgba.Rgb = pal[index]; + int index = scanlineSpan[o]; + rgba.Rgb = palettePixels[index]; - color.PackFromRgba32(rgba); - rowSpan[x] = color; + pixel.PackFromRgba32(rgba); + rowSpan[x] = pixel; } } @@ -1053,15 +1056,15 @@ namespace SixLabors.ImageSharp.Formats.Png Rgba64 rgba64 = default; for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 6) { - rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2)); - rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2)); - rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 4, 2)); + 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; - color.PackFromRgba64(rgba64); - rowSpan[x] = color; + pixel.PackFromRgba64(rgba64); + rowSpan[x] = pixel; } } else @@ -1069,11 +1072,11 @@ namespace SixLabors.ImageSharp.Formats.Png Rgb48 rgb48 = default; for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 6) { - rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2)); - rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2)); - rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 4, 2)); - color.PackFromRgb48(rgb48); - rowSpan[x] = color; + 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; } } } @@ -1084,13 +1087,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 = scanlineBuffer[o]; - rgba.G = scanlineBuffer[o + this.bytesPerSample]; - rgba.B = scanlineBuffer[o + (2 * this.bytesPerSample)]; + rgba.R = scanlineSpan[o]; + rgba.G = scanlineSpan[o + this.bytesPerSample]; + rgba.B = scanlineSpan[o + (2 * this.bytesPerSample)]; rgba.A = this.rgb24Trans.Equals(rgba.Rgb) ? byte.MinValue : byte.MaxValue; - color.PackFromRgba32(rgba); - rowSpan[x] = color; + pixel.PackFromRgba32(rgba); + rowSpan[x] = pixel; } } else @@ -1098,12 +1101,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 = scanlineBuffer[o]; - rgba.G = scanlineBuffer[o + this.bytesPerSample]; - rgba.B = scanlineBuffer[o + (2 * this.bytesPerSample)]; + rgba.R = scanlineSpan[o]; + rgba.G = scanlineSpan[o + this.bytesPerSample]; + rgba.B = scanlineSpan[o + (2 * this.bytesPerSample)]; - color.PackFromRgba32(rgba); - rowSpan[x] = color; + pixel.PackFromRgba32(rgba); + rowSpan[x] = pixel; } } } @@ -1117,12 +1120,12 @@ namespace SixLabors.ImageSharp.Formats.Png Rgba64 rgba64 = default; for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 8) { - rgba64.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2)); - rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2)); - rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 4, 2)); - rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 6, 2)); - color.PackFromRgba64(rgba64); - rowSpan[x] = color; + 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); + rowSpan[x] = pixel; } } else @@ -1130,18 +1133,20 @@ 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 = scanlineBuffer[o]; - rgba.G = scanlineBuffer[o + this.bytesPerSample]; - rgba.B = scanlineBuffer[o + (2 * this.bytesPerSample)]; - rgba.A = scanlineBuffer[o + (3 * this.bytesPerSample)]; + rgba.R = scanlineSpan[o]; + rgba.G = scanlineSpan[o + this.bytesPerSample]; + rgba.B = scanlineSpan[o + (2 * this.bytesPerSample)]; + rgba.A = scanlineSpan[o + (3 * this.bytesPerSample)]; - color.PackFromRgba32(rgba); - rowSpan[x] = color; + pixel.PackFromRgba32(rgba); + rowSpan[x] = pixel; } } break; } + + buffer?.Dispose(); } /// @@ -1193,13 +1198,12 @@ namespace SixLabors.ImageSharp.Formats.Png /// Processes a scanline that uses a palette /// /// The type of pixel we are expanding to - /// The scanline + /// The defiltered scanline /// Thecurrent output image row - private void ProcessScanlineFromPalette(ReadOnlySpan defilteredScanline, Span row) + private void ProcessScanlineFromPalette(ReadOnlySpan scanline, Span row) where TPixel : struct, IPixel { - ReadOnlySpan newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth); - ReadOnlySpan pal = MemoryMarshal.Cast(this.palette); + ReadOnlySpan palettePixels = MemoryMarshal.Cast(this.palette); var color = default(TPixel); if (this.paletteAlpha?.Length > 0) @@ -1210,9 +1214,9 @@ namespace SixLabors.ImageSharp.Formats.Png // channel and we should try to read it. for (int x = 0; x < this.header.Width; x++) { - int index = newScanline[x]; + int index = scanline[x]; rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : byte.MaxValue; - rgba.Rgb = pal[index]; + rgba.Rgb = palettePixels[index]; color.PackFromRgba32(rgba); row[x] = color; @@ -1220,13 +1224,13 @@ 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 < this.header.Width; x++) { - int index = newScanline[x]; + int index = scanline[x]; - rgba.Rgb = pal[index]; + rgba.Rgb = palettePixels[index]; color.PackFromRgba32(rgba); row[x] = color; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 348b3b185..7286539f7 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -44,14 +44,14 @@ namespace SixLabors.ImageSharp.Tests // IDAT 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41, 0x54, 0x18, 0x57, 0x63, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, - + // IDAT CRC 0x5C, 0xCD, 0xFF, 0x69, // IEND 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, - + // IEND CRC 0xAE, 0x42, 0x60, 0x82 }; @@ -76,7 +76,6 @@ namespace SixLabors.ImageSharp.Tests TestImages.Png.VimImage2, }; - public static readonly string[] TestImages48Bpp = { TestImages.Png.Rgb48Bpp, From 973000fd093c5493f0407d82e0efe07a0f9f57f0 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 18 Jun 2018 22:23:39 +1000 Subject: [PATCH 24/30] Use Rgba64 for image comparison. --- .../Formats/Jpg/JpegDecoderTests.cs | 2 +- .../Processors/Convolution/DetectEdgesTest.cs | 2 +- .../Processors/Filters/FilterTest.cs | 2 +- .../Processors/Transforms/ResizeTests.cs | 2 +- .../Transforms/AffineTransformTests.cs | 2 +- .../ImageComparison/ExactImageComparer.cs | 14 ++++---- ...ImageDifferenceIsOverThresholdException.cs | 2 +- .../ImageComparison/ImageComparer.cs | 19 +++++----- .../ImageComparison/ImageSimilarityReport.cs | 4 ++- .../ImageComparison/PixelDifference.cs | 10 +++--- .../ImageComparison/TolerantImageComparer.cs | 35 ++++++++++--------- .../TestUtilities/ImagingTestCaseUtility.cs | 19 +++++----- .../TestUtilities/Tests/ImageComparerTests.cs | 18 +++++----- 13 files changed, 67 insertions(+), 64 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 6b3ef1dee..41cc6db51 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg if (!CustomToleranceValues.TryGetValue(file, out float tolerance)) { - bool baseline = file.ToLower().Contains("baseline"); + bool baseline = file.IndexOf("baseline", StringComparison.OrdinalIgnoreCase) >= 0; tolerance = baseline ? BaselineTolerance : ProgressiveTolerance; } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs index 6894f9b9b..ae172a0bf 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution public class DetectEdgesTest : FileTestBase { - private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.001f); + private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.0456F); public static readonly string[] CommonTestImages = { TestImages.Png.Bike }; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Filters/FilterTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Filters/FilterTest.cs index 8a2404656..d275c1b1a 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Filters/FilterTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Filters/FilterTest.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Filters [GroupOutput("Filters")] public class FilterTest { - private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.005f, 3); + private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.0218f, 3); // Testing the generic FilterProcessor with more than one pixel type intentionally. // There is no need to do this with the specialized ones. diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index 3fc22264d..6a6dc45f7 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { public static readonly string[] CommonTestImages = { TestImages.Png.CalliphoraPartial }; - private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.005f); + private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.069F); public static readonly TheoryData AllReSamplers = new TheoryData diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index 3232c848e..852dfd9d5 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { private readonly ITestOutputHelper Output; - private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.005f, 3); + private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.0085f, 3); /// /// angleDeg, sx, sy, tx, ty diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs index 5ed69f43d..8dca11cae 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs @@ -22,10 +22,10 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison int width = actual.Width; - // TODO: Comparing through Rgba32 is not robust enough because of the existance of super high precision pixel types. + // TODO: Comparing through Rgba64 may not be robust enough because of the existance of super high precision pixel types. - var aBuffer = new Rgba32[width]; - var bBuffer = new Rgba32[width]; + var aBuffer = new Rgba64[width]; + var bBuffer = new Rgba64[width]; var differences = new List(); @@ -34,13 +34,13 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison Span aSpan = expected.GetPixelRowSpan(y); Span bSpan = actual.GetPixelRowSpan(y); - PixelOperations.Instance.ToRgba32(aSpan, aBuffer, width); - PixelOperations.Instance.ToRgba32(bSpan, bBuffer, width); + PixelOperations.Instance.ToRgba64(aSpan, aBuffer, width); + PixelOperations.Instance.ToRgba64(bSpan, bBuffer, width); for (int x = 0; x < width; x++) { - Rgba32 aPixel = aBuffer[x]; - Rgba32 bPixel = bBuffer[x]; + Rgba64 aPixel = aBuffer[x]; + Rgba64 bPixel = bBuffer[x]; if (aPixel != bPixel) { diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/Exceptions/ImageDifferenceIsOverThresholdException.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/Exceptions/ImageDifferenceIsOverThresholdException.cs index 8b0c3969c..d000f7093 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/Exceptions/ImageDifferenceIsOverThresholdException.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/Exceptions/ImageDifferenceIsOverThresholdException.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison int i = 0; foreach (ImageSimilarityReport r in reports) { - sb.Append($"Report{i}: "); + sb.Append($"Report ImageFrame {i}: "); sb.Append(r); sb.Append(Environment.NewLine); i++; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs index bb5d0e6dd..38dada063 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs @@ -28,9 +28,8 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison /// /// Returns Tolerant(imageThresholdInPercents/100) /// - public static ImageComparer TolerantPercentage(float imageThresholdInPercents, - int perPixelManhattanThreshold = 0) => - Tolerant(imageThresholdInPercents / 100f, perPixelManhattanThreshold); + public static ImageComparer TolerantPercentage(float imageThresholdInPercents, int perPixelManhattanThreshold = 0) + => Tolerant(imageThresholdInPercents / 100F, perPixelManhattanThreshold); public abstract ImageSimilarityReport CompareImagesOrFrames( ImageFrame expected, @@ -120,18 +119,20 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison var cleanedReports = new List>(reports.Count()); foreach (ImageSimilarityReport r in reports) { - IEnumerable outsideChanges = r.Differences.Where(x => !( - ignoredRegion.X <= x.Position.X && - x.Position.X <= ignoredRegion.Right && - ignoredRegion.Y <= x.Position.Y && - x.Position.Y <= ignoredRegion.Bottom)); + IEnumerable outsideChanges = r.Differences.Where( + x => + !(ignoredRegion.X <= x.Position.X + && x.Position.X <= ignoredRegion.Right + && ignoredRegion.Y <= x.Position.Y + && x.Position.Y <= ignoredRegion.Bottom)); + if (outsideChanges.Any()) { cleanedReports.Add(new ImageSimilarityReport(r.ExpectedImage, r.ActualImage, outsideChanges, null)); } } - if (cleanedReports.Any()) + if (cleanedReports.Count > 0) { throw new ImageDifferenceIsOverThresholdException(cleanedReports); } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageSimilarityReport.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageSimilarityReport.cs index 7465d61b8..f53407976 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageSimilarityReport.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageSimilarityReport.cs @@ -19,6 +19,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison this.TotalNormalizedDifference = totalNormalizedDifference; this.Differences = differences.ToArray(); } + public object ExpectedImage { get; } public object ActualImage { get; } @@ -59,6 +60,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison var sb = new StringBuilder(); if (this.TotalNormalizedDifference.HasValue) { + sb.AppendLine(); sb.AppendLine($"Total difference: {this.DifferencePercentageString}"); } int max = Math.Min(5, this.Differences.Length); @@ -68,7 +70,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison sb.Append(this.Differences[i]); if (i < max - 1) { - sb.Append("; "); + sb.AppendFormat(";{0}", Environment.NewLine); } } if (this.Differences.Length >= 5) diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/PixelDifference.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/PixelDifference.cs index c1f79c619..1ffeb60ad 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/PixelDifference.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/PixelDifference.cs @@ -19,12 +19,12 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison this.AlphaDifference = alphaDifference; } - public PixelDifference(Point position, Rgba32 expected, Rgba32 actual) + public PixelDifference(Point position, Rgba64 expected, Rgba64 actual) : this(position, - (int)actual.R - (int)expected.R, - (int)actual.G - (int)expected.G, - (int)actual.B - (int)expected.B, - (int)actual.A - (int)expected.A) + actual.R - expected.R, + actual.G - expected.G, + actual.B - expected.B, + actual.A - expected.A) { } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs index 667e90cfb..ccc509470 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs @@ -12,7 +12,8 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison public class TolerantImageComparer : ImageComparer { // 1% of all pixels in a 100*100 pixel area are allowed to have a difference of 1 unit - public const float DefaultImageThreshold = 1.0f / (100 * 100 * 255); + // 257 = (1 / 255) * 65535. + public const float DefaultImageThreshold = 257F / (100 * 100 * 65535); /// /// Individual manhattan pixel difference is only added to total image difference when the individual difference is over 'perPixelManhattanThreshold'. @@ -28,23 +29,23 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison /// /// The maximal tolerated difference represented by a value between 0.0 and 1.0. /// Examples of percentage differences on a single pixel: - /// 1. PixelA = (255,255,255,0) PixelB =(0,0,0,255) leads to 100% difference on a single pixel - /// 2. PixelA = (255,255,255,0) PixelB =(255,255,255,255) leads to 25% difference on a single pixel - /// 3. PixelA = (255,255,255,0) PixelB =(128,128,128,128) leads to 50% difference on a single pixel + /// 1. PixelA = (65535,65535,65535,0) PixelB =(0,0,0,65535) leads to 100% difference on a single pixel + /// 2. PixelA = (65535,65535,65535,0) PixelB =(65535,65535,65535,65535) leads to 25% difference on a single pixel + /// 3. PixelA = (65535,65535,65535,0) PixelB =(128,128,128,128) leads to 50% difference on a single pixel /// /// The total differences is the sum of all pixel differences normalized by image dimensions! /// The individual distances are calculated using the Manhattan function: /// /// https://en.wikipedia.org/wiki/Taxicab_geometry /// - /// ImageThresholdInPercents = 1.0/255 means that we allow one byte difference per channel on a 1x1 image - /// ImageThresholdInPercents = 1.0/(100*100*255) means that we allow only one byte difference per channel on a 100x100 image + /// ImageThresholdInPercents = 1.0/65535 means that we allow one unit difference per channel on a 1x1 image + /// ImageThresholdInPercents = 1.0/(100*100*65535) means that we allow only one unit difference per channel on a 100x100 image /// public float ImageThreshold { get; } /// /// The threshold of the individual pixels before they acumulate towards the overall difference. - /// For an individual pixel pair the value is the Manhattan distance of pixels: + /// For an individual pixel pair the value is the Manhattan distance of pixels: /// /// https://en.wikipedia.org/wiki/Taxicab_geometry /// @@ -60,12 +61,12 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison int width = actual.Width; - // TODO: Comparing through Rgba32 is not robust enough because of the existance of super high precision pixel types. + // TODO: Comparing through Rgba64 may not robust enough because of the existance of super high precision pixel types. - var aBuffer = new Rgba32[width]; - var bBuffer = new Rgba32[width]; + var aBuffer = new Rgba64[width]; + var bBuffer = new Rgba64[width]; - float totalDifference = 0.0f; + float totalDifference = 0F; var differences = new List(); @@ -74,8 +75,8 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison Span aSpan = expected.GetPixelRowSpan(y); Span bSpan = actual.GetPixelRowSpan(y); - PixelOperations.Instance.ToRgba32(aSpan, aBuffer, width); - PixelOperations.Instance.ToRgba32(bSpan, bBuffer, width); + PixelOperations.Instance.ToRgba64(aSpan, aBuffer, width); + PixelOperations.Instance.ToRgba64(bSpan, bBuffer, width); for (int x = 0; x < width; x++) { @@ -91,8 +92,8 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison } } - float normalizedDifference = totalDifference / ((float)actual.Width * (float)actual.Height); - normalizedDifference /= 4.0f * 255.0f; + float normalizedDifference = totalDifference / (actual.Width * (float)actual.Height); + normalizedDifference /= 4F * 65535F; if (normalizedDifference > this.ImageThreshold) { @@ -105,12 +106,12 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int GetManhattanDistanceInRgbaSpace(ref Rgba32 a, ref Rgba32 b) + private static int GetManhattanDistanceInRgbaSpace(ref Rgba64 a, ref Rgba64 b) { return Diff(a.R, b.R) + Diff(a.G, b.G) + Diff(a.B, b.B) + Diff(a.A, b.A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int Diff(byte a, byte b) => Math.Abs(a - b); + private static int Diff(ushort a, ushort b) => Math.Abs(a - b); } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index bfd120fff..2c4eb6c33 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -192,7 +192,7 @@ namespace SixLabors.ImageSharp.Tests { Directory.CreateDirectory(baseDir); } - + for (int i = 0; i < frameCount; i++) { string filePath = $"{baseDir}/{i:D2}.{extension}"; @@ -258,7 +258,7 @@ namespace SixLabors.ImageSharp.Tests this.TestName = methodName; this.OutputSubfolderName = outputSubfolderName; } - + internal string GetTestOutputDir() { string testGroupName = Path.GetFileNameWithoutExtension(this.TestGroupName); @@ -281,25 +281,26 @@ namespace SixLabors.ImageSharp.Tests where TPixel : struct, IPixel { TPixel pixel = img[x, y]; - var rgbaPixel = default(Rgba32); - pixel.ToRgba32(ref rgbaPixel); + Rgba64 rgbaPixel = default; + pixel.ToRgba64(ref rgbaPixel); + ushort change = (ushort)Math.Round((perChannelChange / 255F) * 65535F); if (rgbaPixel.R + perChannelChange <= 255) { - rgbaPixel.R += perChannelChange; + rgbaPixel.R += change; } else { - rgbaPixel.R -= perChannelChange; + rgbaPixel.R -= change; } if (rgbaPixel.G + perChannelChange <= 255) { - rgbaPixel.G += perChannelChange; + rgbaPixel.G += change; } else { - rgbaPixel.G -= perChannelChange; + rgbaPixel.G -= change; } if (rgbaPixel.B + perChannelChange <= 255) @@ -320,7 +321,7 @@ namespace SixLabors.ImageSharp.Tests rgbaPixel.A -= perChannelChange; } - pixel.PackFromRgba32(rgbaPixel); + pixel.PackFromRgba64(rgbaPixel); img[x, y] = pixel; } } diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/ImageComparerTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/ImageComparerTests.cs index 48c1b391a..b9fa70f22 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/ImageComparerTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/ImageComparerTests.cs @@ -68,16 +68,14 @@ namespace SixLabors.ImageSharp.Tests { using (Image clone = image.Clone()) { - byte perChannelChange = 2; + byte perChannelChange = 20; ImagingTestCaseUtility.ModifyPixel(clone, 3, 1, perChannelChange); var comparer = ImageComparer.Tolerant(); ImageDifferenceIsOverThresholdException ex = Assert.ThrowsAny( - () => - { - comparer.VerifySimilarity(image, clone); - }); + () => comparer.VerifySimilarity(image, clone)); + PixelDifference diff = ex.Reports.Single().Differences.Single(); Assert.Equal(new Point(3, 1), diff.Position); } @@ -85,7 +83,7 @@ namespace SixLabors.ImageSharp.Tests } [Theory] - [WithTestPatternImages(100, 100, PixelTypes.Rgba32)] + [WithTestPatternImages(100, 100, PixelTypes.Rgba64)] public void TolerantImageComparer_TestPerPixelThreshold(TestImageProvider provider) where TPixel : struct, IPixel { @@ -93,11 +91,11 @@ namespace SixLabors.ImageSharp.Tests { using (Image clone = image.Clone()) { - ImagingTestCaseUtility.ModifyPixel(clone, 0, 0, 10); - ImagingTestCaseUtility.ModifyPixel(clone, 1, 0, 10); - ImagingTestCaseUtility.ModifyPixel(clone, 2, 0, 10); + ImagingTestCaseUtility.ModifyPixel(clone, 0, 0, 1); + ImagingTestCaseUtility.ModifyPixel(clone, 1, 0, 1); + ImagingTestCaseUtility.ModifyPixel(clone, 2, 0, 1); - var comparer = ImageComparer.Tolerant(perPixelManhattanThreshold: 42); + var comparer = ImageComparer.Tolerant(perPixelManhattanThreshold: 257 * 3); comparer.VerifySimilarity(image, clone); } } From 2d6eafa357f3365f2bd2f8ead0dbc28b74a6ab83 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 18 Jun 2018 22:45:05 +1000 Subject: [PATCH 25/30] Use tolerant comparer. --- tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 7286539f7..6b24e127c 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -20,6 +20,9 @@ namespace SixLabors.ImageSharp.Tests { private const PixelTypes PixelTypes = Tests.PixelTypes.Rgba32 | Tests.PixelTypes.RgbaVector | Tests.PixelTypes.Argb32; + // This should be exact but for some reason it fails in some build environments. + private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.0001F, 26); + // Contains the png marker, IHDR and pHYs chunks of a 1x1 pixel 32bit png 1 a single black pixel. private static readonly byte[] raw1x1PngIHDRAndpHYs = { @@ -202,7 +205,7 @@ namespace SixLabors.ImageSharp.Tests if (!SkipVerification(provider)) { - image.VerifyEncoder(provider, "png", null, encoder, customComparer: ImageComparer.Exact); + image.VerifyEncoder(provider, "png", null, encoder, customComparer: ValidatorComparer); } } } @@ -218,7 +221,7 @@ namespace SixLabors.ImageSharp.Tests if (!SkipVerification(provider)) { - image.VerifyEncoder(provider, "png", null, encoder, customComparer: ImageComparer.Exact); + image.VerifyEncoder(provider, "png", null, encoder, customComparer: ValidatorComparer); } } } From 34d1441892c6d0d98797a30a2966ddbc4c857639 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 19 Jun 2018 23:40:51 +1000 Subject: [PATCH 26/30] Use SD, Better conversion and cleanup SD Bridge. --- src/ImageSharp/PixelFormats/Rgb48.cs | 8 +++- src/ImageSharp/PixelFormats/Rgba64.cs | 8 +++- .../Formats/Png/PngDecoderTests.cs | 8 ++-- .../ImageSharp.Tests/ImageSharp.Tests.csproj | 8 ++-- .../ReferenceCodecs/SystemDrawingBridge.cs | 41 +++++++++++-------- .../SystemDrawingReferenceDecoder.cs | 5 ++- .../SystemDrawingReferenceEncoder.cs | 2 +- .../TestUtilities/TestEnvironment.Formats.cs | 8 +++- .../TestUtilities/TestImageExtensions.cs | 6 +-- .../Tests/ReferenceCodecTests.cs | 28 +++++++------ .../Tests/TestEnvironmentTests.cs | 8 ++-- 11 files changed, 78 insertions(+), 52 deletions(-) diff --git a/src/ImageSharp/PixelFormats/Rgb48.cs b/src/ImageSharp/PixelFormats/Rgb48.cs index e4c1345d2..834006011 100644 --- a/src/ImageSharp/PixelFormats/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/Rgb48.cs @@ -160,7 +160,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void PackFromRgba64(Rgba64 source) => this = source.Rgb; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -225,7 +225,11 @@ 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 = this; + dest.A = ushort.MaxValue; + } /// public override bool Equals(object obj) diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/Rgba64.cs index cdc3f38b2..ad7d2dc9d 100644 --- a/src/ImageSharp/PixelFormats/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/Rgba64.cs @@ -232,11 +232,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void PackFromRgb48(Rgb48 source) + { + this.Rgb = source; + this.A = ushort.MaxValue; + } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + public void ToRgb48(ref Rgb48 dest) => dest = this.Rgb; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 6b24e127c..c3c2cf23e 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -20,8 +20,8 @@ namespace SixLabors.ImageSharp.Tests { private const PixelTypes PixelTypes = Tests.PixelTypes.Rgba32 | Tests.PixelTypes.RgbaVector | Tests.PixelTypes.Argb32; - // This should be exact but for some reason it fails in some build environments. - private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.0001F, 26); + // TODO: Cannot use exact comparer since System.Drawing doesn't preserve more than 32bits. + private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.1302F, 2134); // Contains the png marker, IHDR and pHYs chunks of a 1x1 pixel 32bit png 1 a single black pixel. private static readonly byte[] raw1x1PngIHDRAndpHYs = @@ -173,7 +173,7 @@ namespace SixLabors.ImageSharp.Tests if (!SkipVerification(provider)) { - image.VerifyEncoder(provider, "png", null, encoder, customComparer: ImageComparer.Exact); + image.VerifyEncoder(provider, "png", null, encoder, customComparer: ValidatorComparer); } } } @@ -189,7 +189,7 @@ namespace SixLabors.ImageSharp.Tests if (!SkipVerification(provider)) { - image.VerifyEncoder(provider, "png", null, encoder, customComparer: ImageComparer.Exact); + image.VerifyEncoder(provider, "png", null, encoder, customComparer: ValidatorComparer); } } } diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 139df3972..18db6db9c 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -22,6 +22,11 @@ true + + + + + @@ -49,7 +54,4 @@ PreserveNewest - - - diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs index 1dfb3ba46..c281b50c3 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Drawing; using System.Drawing.Imaging; using SixLabors.ImageSharp.Advanced; @@ -10,26 +11,34 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs { + /// + /// Provides methods to convert to/from System.Drawing bitmaps. + /// public static class SystemDrawingBridge { - internal static unsafe Image FromFromArgb32SystemDrawingBitmap(System.Drawing.Bitmap bmp) + /// + /// Returns an image from the given System.Drawing bitmap. + /// + /// The input bitmap. + /// Thrown if the image pixel format is not of type + internal static unsafe Image From32bppArgbSystemDrawingBitmap(Bitmap bmp) where TPixel : struct, IPixel { int w = bmp.Width; int h = bmp.Height; - var fullRect = new System.Drawing.Rectangle(0, 0, w, h); + var fullRect = new Rectangle(0, 0, w, h); if (bmp.PixelFormat != PixelFormat.Format32bppArgb) { - throw new ArgumentException($"FromFromArgb32SystemDrawingBitmap(): pixel format should be Argb32!", nameof(bmp)); + throw new ArgumentException($"{nameof(From32bppArgbSystemDrawingBitmap)} : pixel format should be {PixelFormat.Format32bppArgb}!", nameof(bmp)); } BitmapData data = bmp.LockBits(fullRect, ImageLockMode.ReadWrite, bmp.PixelFormat); byte* sourcePtrBase = (byte*)data.Scan0; long sourceRowByteCount = data.Stride; - long destRowByteCount = w * sizeof(Argb32); + long destRowByteCount = w * sizeof(Bgra32); var image = new Image(w, h); @@ -41,7 +50,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs { Span row = image.Frames.RootFrame.GetPixelRowSpan(y); - byte* sourcePtr = sourcePtrBase + data.Stride * y; + byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); PixelOperations.Instance.PackFromBgra32(workBuffer.GetSpan(), row, row.Length); @@ -53,19 +62,21 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs } /// - /// TODO: Doesn not work yet! + /// Returns an image from the given System.Drawing bitmap. /// - internal static unsafe Image FromFromRgb24SystemDrawingBitmap(System.Drawing.Bitmap bmp) + /// The input bitmap. + /// Thrown if the image pixel format is not of type + internal static unsafe Image From24bppRgbSystemDrawingBitmap(Bitmap bmp) where TPixel : struct, IPixel { int w = bmp.Width; int h = bmp.Height; - var fullRect = new System.Drawing.Rectangle(0, 0, w, h); + var fullRect = new Rectangle(0, 0, w, h); if (bmp.PixelFormat != PixelFormat.Format24bppRgb) { - throw new ArgumentException($"FromFromArgb32SystemDrawingBitmap(): pixel format should be Rgb24!", nameof(bmp)); + throw new ArgumentException($"{nameof(From24bppRgbSystemDrawingBitmap)}: pixel format should be {PixelFormat.Format24bppRgb}!", nameof(bmp)); } BitmapData data = bmp.LockBits(fullRect, ImageLockMode.ReadWrite, bmp.PixelFormat); @@ -84,12 +95,10 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs { Span row = image.Frames.RootFrame.GetPixelRowSpan(y); - byte* sourcePtr = sourcePtrBase + data.Stride * y; + byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); PixelOperations.Instance.PackFromBgr24(workBuffer.GetSpan(), row, row.Length); - - // FromRgb24(workBuffer.GetSpan(), row); } } } @@ -97,14 +106,14 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs return image; } - internal static unsafe System.Drawing.Bitmap ToSystemDrawingBitmap(Image image) + internal static unsafe Bitmap To32bppArgbSystemDrawingBitmap(Image image) where TPixel : struct, IPixel { int w = image.Width; int h = image.Height; - var resultBitmap = new System.Drawing.Bitmap(w, h, PixelFormat.Format32bppArgb); - var fullRect = new System.Drawing.Rectangle(0, 0, w, h); + var resultBitmap = new Bitmap(w, h, PixelFormat.Format32bppArgb); + var fullRect = new Rectangle(0, 0, w, h); BitmapData data = resultBitmap.LockBits(fullRect, ImageLockMode.ReadWrite, resultBitmap.PixelFormat); byte* destPtrBase = (byte*)data.Scan0; @@ -120,7 +129,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs { Span row = image.Frames.RootFrame.GetPixelRowSpan(y); PixelOperations.Instance.ToBgra32(row, workBuffer.GetSpan(), row.Length); - byte* destPtr = destPtrBase + data.Stride * y; + byte* destPtr = destPtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); } diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs index b1e53cb6a..427a56542 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs { if (sourceBitmap.PixelFormat == System.Drawing.Imaging.PixelFormat.Format32bppArgb) { - return SystemDrawingBridge.FromFromArgb32SystemDrawingBitmap(sourceBitmap); + return SystemDrawingBridge.From32bppArgbSystemDrawingBitmap(sourceBitmap); } using (var convertedBitmap = new System.Drawing.Bitmap( @@ -37,7 +37,8 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs g.DrawImage(sourceBitmap, 0, 0, sourceBitmap.Width, sourceBitmap.Height); } - return SystemDrawingBridge.FromFromArgb32SystemDrawingBitmap(convertedBitmap); + + return SystemDrawingBridge.From32bppArgbSystemDrawingBitmap(convertedBitmap); } } } diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs index ca6f32f5b..912333695 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs public void Encode(Image image, Stream stream) where TPixel : struct, IPixel { - using (System.Drawing.Bitmap sdBitmap = SystemDrawingBridge.ToSystemDrawingBitmap(image)) + using (System.Drawing.Bitmap sdBitmap = SystemDrawingBridge.To32bppArgbSystemDrawingBitmap(image)) { sdBitmap.Save(stream, this.imageFormat); } diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs index f62237936..566c22342 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs @@ -60,10 +60,14 @@ namespace SixLabors.ImageSharp.Tests if (!IsLinux) { - // System.Drawing on Windows can decode 48bit and 64bit pngs but + // TODO: System.Drawing on Windows can decode 48bit and 64bit pngs but // it doesn't preserve the accuracy we require for comparison. // This makes CompareToOriginal method non-useful. - configuration.Configure(new PngConfigurationModule()); + configuration.ConfigureCodecs( + ImageFormats.Png, + SystemDrawingReferenceDecoder.Instance, + SystemDrawingReferenceEncoder.Png, + new PngImageFormatDetector()); configuration.ConfigureCodecs( ImageFormats.Bmp, diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index e135c5d31..016ae7ad2 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -38,15 +38,15 @@ namespace SixLabors.ImageSharp.Tests { Span pixelSpan = frame.GetPixelSpan(); - PixelOperations.Instance.ToVector4(pixelSpan, tempSpan, pixelSpan.Length); + PixelOperations.Instance.ToScaledVector4(pixelSpan, tempSpan, pixelSpan.Length); for (int i = 0; i < tempSpan.Length; i++) { ref Vector4 v = ref tempSpan[i]; - v.W = 1.0f; + v.W = 1F; } - PixelOperations.Instance.PackFromVector4(tempSpan, pixelSpan, pixelSpan.Length); + PixelOperations.Instance.PackFromScaledVector4(tempSpan, pixelSpan, pixelSpan.Length); } } }); diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceCodecTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceCodecTests.cs index 520b8d93f..3ad595b7e 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceCodecTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceCodecTests.cs @@ -1,3 +1,4 @@ +using System.IO; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; @@ -20,12 +21,12 @@ namespace SixLabors.ImageSharp.Tests [Theory] [WithTestPatternImages(20, 20, PixelTypes.Rgba32 | PixelTypes.Bgra32)] - public void ToSystemDrawingBitmap(TestImageProvider provider) + public void To32bppArgbSystemDrawingBitmap(TestImageProvider provider) where TPixel : struct, IPixel { using (Image image = provider.GetImage()) { - using (System.Drawing.Bitmap sdBitmap = SystemDrawingBridge.ToSystemDrawingBitmap(image)) + using (System.Drawing.Bitmap sdBitmap = SystemDrawingBridge.To32bppArgbSystemDrawingBitmap(image)) { string fileName = provider.Utility.GetTestOutputFileName("png"); sdBitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Png); @@ -35,14 +36,14 @@ namespace SixLabors.ImageSharp.Tests [Theory] [WithBlankImages(1, 1, PixelTypes.Rgba32 | PixelTypes.Bgra32)] - public void FromFromArgb32SystemDrawingBitmap(TestImageProvider dummyProvider) + public void From32bppArgbSystemDrawingBitmap(TestImageProvider dummyProvider) where TPixel : struct, IPixel { string path = TestFile.GetInputFileFullPath(TestImages.Png.Splash); using (var sdBitmap = new System.Drawing.Bitmap(path)) { - using (Image image = SystemDrawingBridge.FromFromArgb32SystemDrawingBitmap(sdBitmap)) + using (Image image = SystemDrawingBridge.From32bppArgbSystemDrawingBitmap(sdBitmap)) { image.DebugSave(dummyProvider); } @@ -66,17 +67,20 @@ namespace SixLabors.ImageSharp.Tests [Theory] [WithTestPatternImages(100, 100, PixelTypes.Rgba32)] - public void FromFromArgb32SystemDrawingBitmap2(TestImageProvider provider) + public void From32bppArgbSystemDrawingBitmap2(TestImageProvider provider) where TPixel : struct, IPixel { - if (TestEnvironment.IsLinux) return; + if (TestEnvironment.IsLinux) + { + return; + } string path = SavePng(provider, PngColorType.RgbWithAlpha); using (var sdBitmap = new System.Drawing.Bitmap(path)) { using (Image original = provider.GetImage()) - using (Image resaved = SystemDrawingBridge.FromFromArgb32SystemDrawingBitmap(sdBitmap)) + using (Image resaved = SystemDrawingBridge.From32bppArgbSystemDrawingBitmap(sdBitmap)) { ImageComparer comparer = ImageComparer.Exact; comparer.VerifySimilarity(original, resaved); @@ -85,20 +89,18 @@ namespace SixLabors.ImageSharp.Tests } [Theory] - [WithTestPatternImages(100, 100, PixelTypes.Rgba32)] - public void FromFromRgb24SystemDrawingBitmap2(TestImageProvider provider) + [WithTestPatternImages(100, 100, PixelTypes.Rgb24)] + public void From24bppRgbSystemDrawingBitmap(TestImageProvider provider) where TPixel : struct, IPixel { string path = SavePng(provider, PngColorType.Rgb); using (Image original = provider.GetImage()) { - original.Mutate(c => c.MakeOpaque()); using (var sdBitmap = new System.Drawing.Bitmap(path)) { - using (Image resaved = SystemDrawingBridge.FromFromRgb24SystemDrawingBitmap(sdBitmap)) + using (Image resaved = SystemDrawingBridge.From24bppRgbSystemDrawingBitmap(sdBitmap)) { - resaved.Mutate(c => c.MakeOpaque()); ImageComparer comparer = ImageComparer.Exact; comparer.VerifySimilarity(original, resaved); } @@ -112,7 +114,7 @@ namespace SixLabors.ImageSharp.Tests where TPixel : struct, IPixel { string path = TestFile.GetInputFileFullPath(TestImages.Png.Splash); - using (Image image = Image.Load(path, SystemDrawingReferenceDecoder.Instance)) + using (var image = Image.Load(path, SystemDrawingReferenceDecoder.Instance)) { image.DebugSave(dummyProvider); } diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs index 40338e859..d2ef63a11 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.Tests } [Theory] - [InlineData("lol/foo.png", typeof(PngEncoder))] + [InlineData("lol/foo.png", typeof(SystemDrawingReferenceEncoder))] [InlineData("lol/Rofl.bmp", typeof(SystemDrawingReferenceEncoder))] [InlineData("lol/Baz.JPG", typeof(JpegEncoder))] [InlineData("lol/Baz.gif", typeof(GifEncoder))] @@ -73,11 +73,11 @@ namespace SixLabors.ImageSharp.Tests } [Theory] - [InlineData("lol/foo.png", typeof(PngDecoder))] + [InlineData("lol/foo.png", typeof(SystemDrawingReferenceDecoder))] [InlineData("lol/Rofl.bmp", typeof(SystemDrawingReferenceDecoder))] [InlineData("lol/Baz.JPG", typeof(JpegDecoder))] [InlineData("lol/Baz.gif", typeof(GifDecoder))] - public void GetReferenceDecoder_ReturnsCorrectEncoders_Windows(string fileName, Type expectedDecoderType) + public void GetReferenceDecoder_ReturnsCorrectDecoders_Windows(string fileName, Type expectedDecoderType) { if (TestEnvironment.IsLinux) return; @@ -103,7 +103,7 @@ namespace SixLabors.ImageSharp.Tests [InlineData("lol/Rofl.bmp", typeof(BmpDecoder))] [InlineData("lol/Baz.JPG", typeof(JpegDecoder))] [InlineData("lol/Baz.gif", typeof(GifDecoder))] - public void GetReferenceDecoder_ReturnsCorrectEncoders_Linux(string fileName, Type expectedDecoderType) + public void GetReferenceDecoder_ReturnsCorrectDecoders_Linux(string fileName, Type expectedDecoderType) { if (!TestEnvironment.IsLinux) return; From 6d415b5d0d2bae8aed19ed7d84b99a3e3d6fbd90 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 19 Jun 2018 23:45:28 +1000 Subject: [PATCH 27/30] Lol Whut? --- tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 18db6db9c..2a5385e81 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -22,11 +22,6 @@ true - - - - - From 4eb8617739ee018612611fa141ad9021246b93ef Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 21 Jun 2018 14:11:05 +1000 Subject: [PATCH 28/30] Faster 32-64 bit conversion, update references, and cleanup. --- src/ImageSharp/PixelFormats/Argb32.cs | 23 +++++++--- src/ImageSharp/PixelFormats/Bgr24.cs | 29 +++++++----- src/ImageSharp/PixelFormats/Bgra32.cs | 29 +++++++----- src/ImageSharp/PixelFormats/Byte4.cs | 2 +- src/ImageSharp/PixelFormats/Rgb24.cs | 31 +++++++------ src/ImageSharp/PixelFormats/Rgb48.cs | 41 ++++++++--------- src/ImageSharp/PixelFormats/Rgba32.cs | 24 +++++++--- src/ImageSharp/PixelFormats/Rgba64.cs | 44 +++++++++---------- src/ImageSharp/PixelFormats/Short4.cs | 3 +- .../ImageComparison/TolerantImageComparer.cs | 17 ++++--- .../ReferenceCodecs/SystemDrawingBridge.cs | 3 +- .../TestUtilities/TestEnvironment.cs | 2 +- tests/Images/External | 2 +- 13 files changed, 145 insertions(+), 105 deletions(-) diff --git a/src/ImageSharp/PixelFormats/Argb32.cs b/src/ImageSharp/PixelFormats/Argb32.cs index bd4c93d28..ccb17a2a5 100644 --- a/src/ImageSharp/PixelFormats/Argb32.cs +++ b/src/ImageSharp/PixelFormats/Argb32.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.PixelFormats this.R = r; this.G = g; this.B = b; - this.A = 255; + this.A = byte.MaxValue; } /// @@ -312,7 +312,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + 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.A = byte.MaxValue; + } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -320,7 +326,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + 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); + } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -352,8 +364,9 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { - // ReSharper disable once NonReadonlyMemberInGetHashCode - return this.Argb.GetHashCode(); + int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); + hash = HashHelpers.Combine(hash, this.B.GetHashCode()); + return HashHelpers.Combine(hash, this.A.GetHashCode()); } /// diff --git a/src/ImageSharp/PixelFormats/Bgr24.cs b/src/ImageSharp/PixelFormats/Bgr24.cs index 13673aa47..865521084 100644 --- a/src/ImageSharp/PixelFormats/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/Bgr24.cs @@ -69,13 +69,8 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { - unchecked - { - int hashCode = this.B; - hashCode = (hashCode * 397) ^ this.G; - hashCode = (hashCode * 397) ^ this.R; - return hashCode; - } + int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); + return HashHelpers.Combine(hash, this.B.GetHashCode()); } /// @@ -149,7 +144,7 @@ namespace SixLabors.ImageSharp.PixelFormats dest.R = this.R; dest.G = this.G; dest.B = this.B; - dest.A = 255; + dest.A = byte.MaxValue; } /// @@ -159,7 +154,7 @@ namespace SixLabors.ImageSharp.PixelFormats dest.R = this.R; dest.G = this.G; dest.B = this.B; - dest.A = 255; + dest.A = byte.MaxValue; } /// @@ -174,12 +169,17 @@ namespace SixLabors.ImageSharp.PixelFormats dest.R = this.R; dest.G = this.G; dest.B = this.B; - dest.A = 255; + dest.A = byte.MaxValue; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + 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); + } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -187,7 +187,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + 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); + } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/Bgra32.cs b/src/ImageSharp/PixelFormats/Bgra32.cs index 86a141bc5..f951be881 100644 --- a/src/ImageSharp/PixelFormats/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/Bgra32.cs @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.PixelFormats this.R = r; this.G = g; this.B = b; - this.A = 255; + this.A = byte.MaxValue; } /// @@ -113,14 +113,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// public override int GetHashCode() { - unchecked - { - int hashCode = this.B; - hashCode = (hashCode * 397) ^ this.G; - hashCode = (hashCode * 397) ^ this.R; - hashCode = (hashCode * 397) ^ this.A; - return hashCode; - } + int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); + hash = HashHelpers.Combine(hash, this.B.GetHashCode()); + return HashHelpers.Combine(hash, this.A.GetHashCode()); } /// @@ -248,7 +243,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + 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.A = byte.MaxValue; + } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -256,7 +257,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + 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); + } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/Byte4.cs b/src/ImageSharp/PixelFormats/Byte4.cs index 48430d17a..426955727 100644 --- a/src/ImageSharp/PixelFormats/Byte4.cs +++ b/src/ImageSharp/PixelFormats/Byte4.cs @@ -198,7 +198,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// public override bool Equals(object obj) { - return (obj is Byte4) && this.Equals((Byte4)obj); + return obj is Byte4 byte4 && this.Equals(byte4); } /// diff --git a/src/ImageSharp/PixelFormats/Rgb24.cs b/src/ImageSharp/PixelFormats/Rgb24.cs index c3ad82755..4c7ad5909 100644 --- a/src/ImageSharp/PixelFormats/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/Rgb24.cs @@ -70,13 +70,8 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { - unchecked - { - int hashCode = this.R; - hashCode = (hashCode * 397) ^ this.G; - hashCode = (hashCode * 397) ^ this.B; - return hashCode; - } + int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); + return HashHelpers.Combine(hash, this.B.GetHashCode()); } /// @@ -131,7 +126,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 ToVector4() { - return new Rgba32(this.R, this.G, this.B, 255).ToVector4(); + return new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4(); } /// @@ -142,7 +137,7 @@ namespace SixLabors.ImageSharp.PixelFormats public void ToRgba32(ref Rgba32 dest) { dest.Rgb = this; - dest.A = 255; + dest.A = byte.MaxValue; } /// @@ -151,7 +146,7 @@ namespace SixLabors.ImageSharp.PixelFormats dest.R = this.R; dest.G = this.G; dest.B = this.B; - dest.A = 255; + dest.A = byte.MaxValue; } /// @@ -168,12 +163,17 @@ namespace SixLabors.ImageSharp.PixelFormats dest.R = this.R; dest.G = this.G; dest.B = this.B; - dest.A = 255; + dest.A = byte.MaxValue; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + 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); + } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -181,7 +181,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + 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); + } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/Rgb48.cs b/src/ImageSharp/PixelFormats/Rgb48.cs index 834006011..2d92b0e4e 100644 --- a/src/ImageSharp/PixelFormats/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/Rgb48.cs @@ -166,53 +166,48 @@ namespace SixLabors.ImageSharp.PixelFormats [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); + 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) { - 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); + 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) { - 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); + 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) { - 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.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) { - 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); + 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; } /// diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index c585dbfda..79794ee46 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats this.R = r; this.G = g; this.B = b; - this.A = 255; + this.A = byte.MaxValue; } /// @@ -389,7 +389,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + 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.A = byte.MaxValue; + } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -397,7 +403,14 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + 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); + } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -426,8 +439,9 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { - // ReSharper disable once NonReadonlyMemberInGetHashCode - return this.Rgba.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()); } /// diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/Rgba64.cs index ad7d2dc9d..b0aeab92e 100644 --- a/src/ImageSharp/PixelFormats/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/Rgba64.cs @@ -170,7 +170,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 ToVector4() { - return new Vector4(this.R / Max, this.G / Max, this.B / Max, this.A / Max); + return new Vector4(this.R, this.G, this.B, this.A) / Max; } /// @@ -213,21 +213,20 @@ namespace SixLabors.ImageSharp.PixelFormats [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); + 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) { - 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); + // 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); } /// @@ -250,32 +249,29 @@ namespace SixLabors.ImageSharp.PixelFormats [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); + 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 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); + 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) { - 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); + 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); } /// diff --git a/src/ImageSharp/PixelFormats/Short4.cs b/src/ImageSharp/PixelFormats/Short4.cs index 41371362e..5683ffcee 100644 --- a/src/ImageSharp/PixelFormats/Short4.cs +++ b/src/ImageSharp/PixelFormats/Short4.cs @@ -295,8 +295,7 @@ namespace SixLabors.ImageSharp.PixelFormats vector *= 255; vector += Half; vector += Round; - 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/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs index ccc509470..674603380 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs @@ -18,6 +18,8 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison /// /// Individual manhattan pixel difference is only added to total image difference when the individual difference is over 'perPixelManhattanThreshold'. /// + /// The maximal tolerated difference represented by a value between 0.0 and 1.0 scaled to 0 and 65535. + /// Gets the threshold of the individual pixels before they acumulate towards the overall difference. public TolerantImageComparer(float imageThreshold, int perPixelManhattanThreshold = 0) { Guard.MustBeGreaterThanOrEqualTo(imageThreshold, 0, nameof(imageThreshold)); @@ -27,24 +29,27 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison } /// - /// The maximal tolerated difference represented by a value between 0.0 and 1.0. + /// + /// Gets the maximal tolerated difference represented by a value between 0.0 and 1.0 scaled to 0 and 65535. /// Examples of percentage differences on a single pixel: /// 1. PixelA = (65535,65535,65535,0) PixelB =(0,0,0,65535) leads to 100% difference on a single pixel /// 2. PixelA = (65535,65535,65535,0) PixelB =(65535,65535,65535,65535) leads to 25% difference on a single pixel - /// 3. PixelA = (65535,65535,65535,0) PixelB =(128,128,128,128) leads to 50% difference on a single pixel - /// + /// 3. PixelA = (65535,65535,65535,0) PixelB =(32767,32767,32767,32767) leads to 50% difference on a single pixel + /// + /// /// The total differences is the sum of all pixel differences normalized by image dimensions! /// The individual distances are calculated using the Manhattan function: /// /// https://en.wikipedia.org/wiki/Taxicab_geometry /// - /// ImageThresholdInPercents = 1.0/65535 means that we allow one unit difference per channel on a 1x1 image - /// ImageThresholdInPercents = 1.0/(100*100*65535) means that we allow only one unit difference per channel on a 100x100 image + /// ImageThresholdInPercents = 1/255 = 257/65535 means that we allow one unit difference per channel on a 1x1 image + /// ImageThresholdInPercents = 1/(100*100*255) = 257/(100*100*65535) means that we allow only one unit difference per channel on a 100x100 image + /// /// public float ImageThreshold { get; } /// - /// The threshold of the individual pixels before they acumulate towards the overall difference. + /// Gets the threshold of the individual pixels before they acumulate towards the overall difference. /// For an individual pixel pair the value is the Manhattan distance of pixels: /// /// https://en.wikipedia.org/wiki/Taxicab_geometry diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs index c281b50c3..f0daa0abb 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs @@ -19,6 +19,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs /// /// Returns an image from the given System.Drawing bitmap. /// + /// The pixel format. /// The input bitmap. /// Thrown if the image pixel format is not of type internal static unsafe Image From32bppArgbSystemDrawingBitmap(Bitmap bmp) @@ -64,6 +65,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs /// /// Returns an image from the given System.Drawing bitmap. /// + /// The pixel format. /// The input bitmap. /// Thrown if the image pixel format is not of type internal static unsafe Image From24bppRgbSystemDrawingBitmap(Bitmap bmp) @@ -124,7 +126,6 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs { fixed (Bgra32* sourcePtr = &workBuffer.GetReference()) { - for (int y = 0; y < h; y++) { Span row = image.Frames.RootFrame.GetPixelRowSpan(y); diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs index 4cee650e8..d76637886 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Tests () => { bool isCi; - return Boolean.TryParse(Environment.GetEnvironmentVariable("CI"), out isCi) && isCi; + return bool.TryParse(Environment.GetEnvironmentVariable("CI"), out isCi) && isCi; }); // ReSharper disable once InconsistentNaming diff --git a/tests/Images/External b/tests/Images/External index 147306294..94cc43a65 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 147306294437dc03f6e640f5db2dcd496a43ced7 +Subproject commit 94cc43a65e304aa312bea9d098206086095e6dff From 5da41842177d7e4871beecf8672c3143e6cf1483 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 21 Jun 2018 17:16:42 +1000 Subject: [PATCH 29/30] Better tRNS coverage --- .../Formats/Png/PngDecoderTests.cs | 3 +++ tests/ImageSharp.Tests/TestImages.cs | 4 +++- tests/Images/Input/Png/gray-16-tRNS.png | Bin 684 -> 1448 bytes tests/Images/Input/Png/rgb-16-tRNS.png | Bin 0 -> 2624 bytes tests/Images/Input/Png/rgb-8-tRNS.png | Bin 0 -> 1624 bytes 5 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 tests/Images/Input/Png/rgb-16-tRNS.png create mode 100644 tests/Images/Input/Png/rgb-8-tRNS.png diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index c3c2cf23e..8162d61bd 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -77,6 +77,8 @@ namespace SixLabors.ImageSharp.Tests TestImages.Png.Bad.ChunkLength2, TestImages.Png.VimImage2, + + TestImages.Png.Rgb24BppTrans, }; public static readonly string[] TestImages48Bpp = @@ -88,6 +90,7 @@ namespace SixLabors.ImageSharp.Tests public static readonly string[] TestImages64Bpp = { TestImages.Png.Rgba64Bpp, + TestImages.Png.Rgb48BppTrans }; public static readonly string[] TestImagesGray16Bit = diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index d965b01d7..8722c8b48 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -30,13 +30,15 @@ namespace SixLabors.ImageSharp.Tests public const string Gray16Bit = "Png/gray-16.png"; public const string GrayAlpha16Bit = "Png/gray-alpha-16.png"; public const string GrayTrns16Bit = "Png/gray-16-tRNS.png"; + public const string Rgb24BppTrans = "Png/rgb-8-tRNS.png"; public const string Rgb48Bpp = "Png/rgb-48bpp.png"; + public const string Rgb48BppInterlaced = "Png/rgb-48bpp-interlaced.png"; + public const string Rgb48BppTrans = "Png/rgb-16-tRNS.png"; public const string Rgba64Bpp = "Png/rgb-16-alpha.png"; public const string CalliphoraPartial = "Png/CalliphoraPartial.png"; public const string CalliphoraPartialGrayscale = "Png/CalliphoraPartialGrayscale.png"; public const string Bike = "Png/Bike.png"; public const string BikeGrayscale = "Png/BikeGrayscale.png"; - public const string Rgb48BppInterlaced = "Png/rgb-48bpp-interlaced.png"; public const string SnakeGame = "Png/SnakeGame.png"; public const string Icon = "Png/icon.png"; public const string Kaboom = "Png/kaboom.png"; diff --git a/tests/Images/Input/Png/gray-16-tRNS.png b/tests/Images/Input/Png/gray-16-tRNS.png index 4826d61eb7fab6977de0135762596f6220847a51..4b7537e30508560b833f3d2da7dc8c620a34c301 100644 GIT binary patch literal 1448 zcmV;Z1y}lsP)Ea|c38asIKZwJ|` ztSq3EQc4L~ytwn!<>xsV0D#@Qlf&bW>#hL+Nc8%XC(SDd?R|P&Ri-?glOv&YUqPVR z<#ISKd}0PyJOgn1XsS--P z-c=u}_#yK-&g1E{qLkA5dY%snId_f)kjrU1K7cMta-MBZiI7UKUpEy$&S#JM)RsN| z)O`n@{OE`>1@ZSq5g~hPZKCXL2dA9Rvi>wgad{hilnSj&rWScT2QTs(woLI$V<3Q^ z&+8bF;w^AHQ>FR~obzjK-e#m-^8gOwVg&8g!sxDpPlByO-E-SQR5*y)Z^z9t8Rc(up&&mo5V*qa4P%81lL4(qBQ{z&-M)gY#wBA}T5PkuaLaLKv)5Zx1i%8Q-U!)9V`Oo|h5?w(lzP2& zpO&8D|B4OrXVJeu{|}@SqKncUiHSkTV5s<3$dgEw20tM-mW{Ugo=ug1!^|MWdy}ED#z`3J;_CgQWW^`(B0&WBb|h9 z&04cPB&%Oxd3kelX{k)sN3-^Bn)XZ-0q)#+@!dlK06-8Fik{7U?L52=Y~Rl?3gStB3Xp76L2r&ntk zLKr42Oc3mL&(R8-J>TVwTa~t9z{C-c=dMgh=p}$Nf^^283~suns#-`SX{1JCCIn+b zoK7;z2NXyiD^LmZqh!J?LI5RZUmTme|eavtQD^Zi|G{%Hr>~tD_ z@V2@hj9709b$=m-O82J@oHVJIfK)oV1RYVCz0K|v#=&%8CCSAagb?C+gj!~KF+~IU z$X&AavPY8HU$1^q+OB0-v*y>v2k=2ss>-(mTEuGPI)N>6Zhn zH*s52O3EvC0pq;9n|olDC4FSUV2)udmWBqawchNBo-CZ^!fIbJ%H6?n`T0hpRLU?7 z4OT0qnVAa~Fic;}S8iiNLqUN~r_m%P{x|1;uk*j3h8*&ox4E1E0000Q)?6_t8Wt(r^S91+lJYzG)57?=|n qcp4Z7m@_CG0SSfy4hgU$t}`7;V&*H`p}d0u2s~Z=T-G@yGywqIAfV*{ diff --git a/tests/Images/Input/Png/rgb-16-tRNS.png b/tests/Images/Input/Png/rgb-16-tRNS.png new file mode 100644 index 0000000000000000000000000000000000000000..64a9cdf2f7fb4015cfededee285d015f96330cc7 GIT binary patch literal 2624 zcmW;Odpy&79{}+0hMu{k(M};WMJ>4<_rok=GIGCPva%4Wg9urf`~5cIkucp{H?yeuYu9?5XL7|Vg@G%1#crW%*_;D~afi81aAE1Og)sZ&`U zR~u4OQc?!zPC~{MKR>^j_;9AM3s04ue732g5?6`X_RhVxP#k+2WGT1H8r0PTj4MzK71Itd_F#GHc|+i?J1#yxK760*KMJinq;%&VV??h8kfey_bGIGH4M!LDJd%} zYiaNyBSGiKBn3yuXrvX6@dODL@t47pHV*Xmip5Z(GN0r@QCyebCC#>Ch<6d`~M3*HcmEe;0i^88tDjWX#_3JNklEU#}h2=gvl7ztT zA2LHnU{7KAm`hrEilPBJ1r`swV6wWp8XFrma?hesyr2FJ(kbYlf^|Jp1dmK%e)ei` z&e`7D+ESOu@fZ7s(?nJ^@8YSfGxlQd`&ld&?T@Vrp=*sUH4bM< zfF88{Vu-qZ8_VcBfQ*h#Qq|Vh%&|yM6;D;apu_QTw|lar><9S4GoHlYHEs#hK7W37Mh;db4^_$^#fws z(WGiyhIR!ed2&yZ8Bq1*=g*(i@MhRT!MA{E7ZWFIhh*&6exw|k{psNth5$>+;!;@XPzJB3~u}Qyeyo`!HUu>1Y z32U+PZyuemduvfn?>KouAK~QO8X#Fz#8eS-Z~#2GBiy;={|E49n8k_k#vwj%5a8b4 zUGKiR`APp~kw|8`c{ww^;$FQ=MR|F-Kh<}-zs6>&U-5a;EA5Z`Hn(5{RrFp9rcfyC z)hWfBeu4&MSKBJP$3^!ZS65f(=fT{DZPGoRG;9ok!cr8=#3K(e?rnnSuih9H|87nJY8I@HRm6*4*~=^qg4fMgUcD_=B@G z-`om?zJ{R>+^q0<@ZxJegh-Rpz5V269(VqJ5JAB$j2sHX$LK`>-e>@Na5NnK5zfLg z>-%aDoY7b$P2prLPi0?HiNgXB%q_qfDx#hs*(8=5AU3|m!7S8hV-grs(l zrMeaunB`*<(_C|-)#9_H%cprh&^wyW(>-aN?%pX*_t|2{-4m>Oh0gkvLTlIip3Vmr zw|91JE39Vuqp%}4YaFWEpXNcf6|lFSl<|Sfx3WB)f8>&1H8(d)rSYKkMTa}|t9XHa zFTngFWP{Pi3%?6EBFMaPBiq!~6-+D(2T3|&Be=%-&prdxga7PsX(7REaapP}B> zC%v!FW{HU3N5I~*OQ>uL!^0hNzq{H_-d;V4t=-bd2N*p7tgfxCudi!qstUEKd_tfY z^VVdty*>F5mINwAh2pOMby-EC?MkW08|(Y$4G>mng!67`Xoh`ZIb1uj9_h5*ANlTe z14jikAi7bnE@h-63jjeuLntD6YG}pOr%6kFaLzaQS>-7}ai&qF+m^#}&x!@TyghtY zq9r4Sd*n$3Cfq266DEC->RxAB_TJMOPNk__6gHu_ShA?|pfD2r;ejFgh$bFBZShb{ zEYuR2t4wa8ZZ5CQXlM-79hY*tq<80e#f6;kJHx{#GGA!YQ;bYR8MX6@2qJ>vLoA*$ zMP?tgqsyMjLI6}eEFFvGrCL*4TPv*_r#d<~IJmL19)Th%oh} z(<@3#?Ub^Y!#ZV>CzjY3(xvqtJj92?-JgCg?(Seqiz!2JtkG|v_EIxk9oIEoL)NPu zM@My8<6in>p4p<@aSPv-WcuSJ>@gGO?YzhWse*!H)+(emz6y)BFuFFL1yt3)xxKl= z-L@1;TN{ObkVQ5l|5gJ$R9GRx@f8yFba+n@voYaBy8B;4J4ZlR^7rnWNI zqzI*^ZZo52-xb+grR#*ukG#CadDumc2-Z1$YGgixBmTH3f9AByue^ti+)LZ}&)tId WtY3e({0;sk1SFz`QSJH5QU3=T4Dpo! literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Png/rgb-8-tRNS.png b/tests/Images/Input/Png/rgb-8-tRNS.png new file mode 100644 index 0000000000000000000000000000000000000000..08ebbae2c8cc7ba70c0104a0abefd746475fe44b GIT binary patch literal 1624 zcmV-e2B-OnP)K~zY`wU*CM8)q8Fzcb^pJwL!dFa}aXFkpy@smTvEg-cUu)kIxI zi<0J;s?v%@sezdbXa z@yxt?m?R{-rjSbgYAz$q`~5u6^FHr84@C&UZz=jWb$>I!=H}+Y!a}7|c_V;r-!C$m zOgtXHd-v}4_BNN#yOYTy?d`#H=LXK5^Y!)ZyPVo<4~oTNB9T~FSXf_Qx5=_AnRKtN zGKE4Nr~oa1pQ4!ihQncp!_fp#uh*BBmhRubpG+nV!{D-6 zA(0SQR|QoS00+n)aL8HNdkLg8?DczD?3 z@$3TP@%YV~Hx)&(UW2oOm+khP-*1kNIz`d)QC0QXvuCm__xJa|R-#-kH#0M17>3PZ$bE(-07X~9Z!zi?RKBfXBbAc zT9qWJNefbxBuSY}ad9z}OopA#tw3O-r>7DQhnpNUr_(9ag_=?WjXOhk-dTIc3Xo-4 zpU>y@dMlMmtyX&(wWevgT&`R;fBf;ILZKD-XRTI#^vFfi#_;g)OWWP6f~IL+=Ai%u zY;0mY)4e|B4X8FpSsh)pfm8DiJ~+KR&awa~xP< zn16J1%nQOJQLOd!XrWN33Bc?1@(PbSumvdissAU1QPhTt7N7*K!I2lzG>s6VD6J14 zeh8Eq=9{sxTr@hs^8<$uAP;5U_-O6#!su z?fpiB2maRAmk|VRaq)NA?4MUw#)pTauQtMK0AAq%paA>~n7CKEXSrJsA;dIILWruW zriu0S_kgm^7He&#=I7tbW_y7rqWG_)M+ch&yk0M-aL@rB+y;jnGJ(vFz5@dwpb2fc zzv!PqMezW4{r*ZiT~yT^5C@7bmpU>svNxd4K?mFzNDW{M=)rnp9VVbbB%!fOvbm%rM(Dy#qLb(PPIB34+iZz%WdwqZ19l1y8}_+w{Q&QYSD0^Lc$t)3nZN zvFHJIfd9DNb+5O<^E_}GxIaGrzrUc@ewhPZ1FXhEgiOhijR<5w1Ps6gF`oleRV9Q- z5)G^|jOldhHrsfuHU?xlF8}VkCw>WV`SRs2ykDGLJ~?8J^l$asx9sSEwFf-mEr8Xd zjYb*RwAqY&zI}Q56yQ2^=&#>>_os=8iC+S+Ec@vnKmGC#Uy7VaH|U{_A=sX0K%2A$ zu*;iwVHldGQ>j!on Date: Thu, 21 Jun 2018 21:26:17 +1000 Subject: [PATCH 30/30] More tests --- .../Formats/Png/PngDecoderTests.cs | 23 ++++++++++-------- .../PixelFormats/Rgb48Tests.cs | 15 ++++++++++++ .../PixelFormats/Rgba64Tests.cs | 17 ++++++++++++- tests/ImageSharp.Tests/TestImages.cs | 3 ++- tests/Images/External | 2 +- ...6-tRNS.png => gray-16-tRNS-interlaced.png} | Bin tests/Images/Input/Png/gray-alpha-8.png | Bin 0 -> 684 bytes 7 files changed, 47 insertions(+), 13 deletions(-) rename tests/Images/Input/Png/{gray-16-tRNS.png => gray-16-tRNS-interlaced.png} (100%) create mode 100644 tests/Images/Input/Png/gray-alpha-8.png diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 8162d61bd..53f71fb7b 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -79,6 +79,7 @@ namespace SixLabors.ImageSharp.Tests TestImages.Png.VimImage2, TestImages.Png.Rgb24BppTrans, + TestImages.Png.GrayAlpha8Bit }; public static readonly string[] TestImages48Bpp = @@ -101,21 +102,23 @@ namespace SixLabors.ImageSharp.Tests public static readonly string[] TestImagesGrayAlpha16Bit = { TestImages.Png.GrayAlpha16Bit, - TestImages.Png.GrayTrns16Bit + TestImages.Png.GrayTrns16BitInterlaced }; // This is a workaround for Mono-s decoder being incompatible with ours and GDI+. // We shouldn't mix these with the Interleaved cases (which are also failing with Mono System.Drawing). Let's go AAA! private static readonly string[] SkipOnMono = - { - TestImages.Png.Bad.ChunkLength2, - TestImages.Png.VimImage2, - TestImages.Png.Splash, - TestImages.Png.Indexed, - TestImages.Png.Bad.ChunkLength1, - TestImages.Png.VersioningImage1, - TestImages.Png.Banner7Adam7InterlaceMode, - }; + { + TestImages.Png.Bad.ChunkLength2, + TestImages.Png.VimImage2, + TestImages.Png.Splash, + TestImages.Png.Indexed, + TestImages.Png.Bad.ChunkLength1, + TestImages.Png.VersioningImage1, + TestImages.Png.Banner7Adam7InterlaceMode, + TestImages.Png.GrayTrns16BitInterlaced, + TestImages.Png.Rgb48BppInterlaced + }; private static bool SkipVerification(ITestImageProvider provider) { diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index ae8cb968a..77d6544f0 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -103,6 +103,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats 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() { diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index 12f4d7afc..92b36a1c6 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -105,6 +105,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats 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() { @@ -155,7 +170,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public void Rgb48_PackFromRgb48_ToRgb48() { // arrange - var input = default(Rgb48); + var input = default(Rgba64); var actual = default(Rgb48); var expected = new Rgb48(65535, 0, 65535); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 8722c8b48..6d3a76e75 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -28,8 +28,9 @@ namespace SixLabors.ImageSharp.Tests public const string Bpp1 = "Png/bpp1.png"; public const string Gray4Bpp = "Png/gray_4bpp.png"; public const string Gray16Bit = "Png/gray-16.png"; + public const string GrayAlpha8Bit = "Png/gray-alpha-8.png"; public const string GrayAlpha16Bit = "Png/gray-alpha-16.png"; - public const string GrayTrns16Bit = "Png/gray-16-tRNS.png"; + public const string GrayTrns16BitInterlaced = "Png/gray-16-tRNS-interlaced.png"; public const string Rgb24BppTrans = "Png/rgb-8-tRNS.png"; public const string Rgb48Bpp = "Png/rgb-48bpp.png"; public const string Rgb48BppInterlaced = "Png/rgb-48bpp-interlaced.png"; diff --git a/tests/Images/External b/tests/Images/External index 94cc43a65..6fcee2ccd 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 94cc43a65e304aa312bea9d098206086095e6dff +Subproject commit 6fcee2ccd5e8bac98a0290b467ad86bb02d00b6c diff --git a/tests/Images/Input/Png/gray-16-tRNS.png b/tests/Images/Input/Png/gray-16-tRNS-interlaced.png similarity index 100% rename from tests/Images/Input/Png/gray-16-tRNS.png rename to tests/Images/Input/Png/gray-16-tRNS-interlaced.png diff --git a/tests/Images/Input/Png/gray-alpha-8.png b/tests/Images/Input/Png/gray-alpha-8.png new file mode 100644 index 0000000000000000000000000000000000000000..eb0a92499810b1da4ca73787f7ca610339f40ddc GIT binary patch literal 684 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K588}#g)VJz{w?Im##5JPCIlrK?C^J2ygkhzE zk%6JH4v;Wa@XF7~Q*bWL%gfA5&q&NwaLO;wNiC`^DgFo4SCSbLQR0)CoSIh*lm;4_ zn#aJvab35^m#KCsyuhD zj#;%@D{=~Y?_KIIn6-IYU;E~gq@uio*>TJG%QoM-uk`SJ+ro3V_8IjhYlzQ2b@>FZ zv5{8OjTvjzfS%ax>EaktaqI0RL!h5H4sYQ7zo_z~gA{k}s`I|5(%B3c*bXpAFfb=D q@H8+EFlSIW0ul@Z91>thTxU9x#LQQ=LwN@S5O})!xvX